I'm trying to allow editing items in an array of strings like so:
http://jsfiddle.net/adamfraser/sr4Fg/44/
<h4> edit </h4>
<ul class="list" data-bind="foreach:titles">
<li class="title" data-bind="editableHTML:$data" contenteditable="true"></li>
</ul>
<h4> view </h4>
<ul class="" data-bind="foreach: titles">
<li class="title" data-bind="text:$data"></li>
</ul>
ko.bindingHandlers.editableHTML = {
init: function(element, valueAccessor) {
var $element = $(element);
var initialValue = ko.utils.unwrapObservable(valueAccessor());
$element.html(initialValue);
$element.on('keyup', function() {
observable = valueAccessor();
observable($element.html());
});
}
};
viewModel= {
titles : ko.observableArray([
"one", "two"
])
};
ko.applyBindings(viewModel);
While the custom editableHTML
handler works for regular (non-array) observables, it's not cutting it for observableArrays. Anyone know why? I'm still new to KO.
You can explicitly point the editableHTML
handler to the parent array (titles
in your case) using custom direction (context
in my code).
Once you have the reference to the parent array you can use the replace
method that is available for each observable array to update the value.
Something like:
ko.bindingHandlers.editableHTML = {
init: function(element, valueAccessor, allBindings) {
var $element = $(element);
var initialValue = ko.utils.unwrapObservable(valueAccessor());
var parentContext = allBindings.get('context');
$element.html(initialValue);
$element.on('keyup', function() {
var curVal = valueAccessor();
var newVal = $element.html();
if (parentContext)
parentContext.replace(curVal, newVal);
else if (ko.isObservable(valueAccessor()))
valueAccessor()(newVal);
});
}
};
Then:
<li class="title"
contenteditable="true"
data-bind="editableHTML: $data, context: $parent.titles"></li>
See Fiddle
Change the titles
array to contain observables instead of plain values, then call the observable upon value change.
For example:
ko.bindingHandlers.editableHTML = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var $element = $(element);
var initialValue = ko.utils.unwrapObservable(valueAccessor());
var origObservable = bindingContext.$rawData;
$element.html(initialValue);
$element.on('keyup', function() {
var curVal = valueAccessor();
var newVal = $element.html();
if (ko.isObservable($origObservable))
origObservable(newVal);
});
}
};
Your updated view-model:
var viewModel = {
titles: ko.observableArray([ko.observable("one"), ko.observable("two")])
};
And the HTML remains the same:
<li class="title"
contenteditable="true"
data-bind="editableHTML: $data"></li>
See Fiddle