KnockoutJS observableArray to update when inner observable is changed - javascript

I need to know how to trigger the update for an observableArray when an observable is changed inside the observableArray.
I have an observableArray that represents a binary tree. I'm using a storage mapping function to get and set the values in the array so it has to be balance even thought it might only contain an empty observable. E.g. nodes()[9] maybe null but when that node is updated I would call nodes()[9](set new value) and need to trigger the observableArray to update

Ended up using .replace() on the observableArray

Managed to look through the code and find observableArray.replace ()
RELATED: How to replace a given index element in knockoutjs

Related

Vuejs2: How to re-render array computed properties when array changed

I have array named List and created computed property computedList for him.
When i update value of array it's not showing in html, but in console i see thar array is updated.
`https://jsfiddle.net/apokjqxx/69/`
What is best way to use computed properties for array?
Maybe is exists way to trigger to re-render computed property?
Due to limitations in JavaScript, Vue cannot detect the changes to an array like this: this.list[1] = 'vueman'
You have to use Vue.set or vm.$set as explained here to trigger state updates in the reactivity system, like follwoing:
this.$set(this.list, 1, 'vueman')
see updated fiddler here.

Asyncronous knockout observableArray select options loading

I hava a selectOptions ajax-based asincronous loader; it accepts remote address and returns an observable array, correctly populated with descriptions and keyvalues to be accepted by the following binding
<select data-bind="value: selectedVal, options: opts, optionsText: 'desc', optionsValue:'key', optionsCaption: ''"/></div>
The fact is that, being asincronous, when I trigger a select options change, based on some user actions, I assign it to my model observable array, I do not get the select popuated, but remains empty.
mymodel.opts = loadOptions("<remoteaddress>");
I know when the second line is called the anwer is not arrived yet, but the returned value is an observableArray, so it should respond correctly whenever is populated, having been assigned to an observable array binded with the ui.
If I hardcode the returned object from the ajax call (when it returns) taking it from console.log in Firefox, or if I pass the observable array opts into the loadOptions, and change it to build up the opts inside it, then it works, but I really need to use loadOptions as is, asincronous. I also tried to append mymodel.opts.valueHasMutated(), but yet ko cannot use the newlly arrived observableArray.
If possible leaving intact the options loader, and if possible without using a custom binding, can I use the incoming observable array for binding when it will be ready?
The problem you've got is that when this line runs:
mymodel.opts = loadOptions("<remoteaddress>");
it's replacing the entire observable array with a different observableArray, rather than updating the current one. You need to update the existing one - can you change loadOptions to return a normal array, rather than an observable one? You can then do:
//clear any existing entries
mymodel.opts.removeAll();
//push the new entries in
mymodel.opts.push.apply(mymodel.opts, loadOptions("<remoteaddress>"));

Knockout - How to recreate a JSON object from modified form [duplicate]

I have a JSON object that I used to create a form. This JSON object is parsed by KnockoutJS.
Now, when I modify the form, I want the JSON object to be updated according to the modifications made in the form. The thing is that I don't know in advance how the form will be like but I know in the JSON Object which fields need to be updated.
I really don't know what is the best way to procede. I know that I could reconstruct the JSON Object each time something has changed but this seems like a bad idea and a tedious process.
Is there a simple way to map each JSON Object field to form items in KnockoutJS ?
Here's a JSFiddle of what I'm currently doing:http://goo.gl/ZBaV7
Update :
I realized something interesting with this line:
<input type="text" data-bind="value: $data.value, attr : { disabled: $data.disabled }" />
I'm accessing the value directly from the array via ($data.value). Is there a way in the html to say to knockout to bind to this particular attribute in the array. I know that if the array would get reordered everything would get messed up but since I know that the only thing that can changed is this property I'm ready to take this risk ?
In other words, is there a way to manually say that when this value changes to change it in the array such as
data-bind="onChange: $data.value = this.value"
Is there a simple way to map each JSON Object field to form items in
KnockoutJS ?
Yes, If I understand what you want to do correctly. As of now, the values in your view model are not observables and won't be updated automatically as the form values change. There is a plugin to handle this mapping.
http://knockoutjs.com/documentation/plugins-mapping.html
Example: Using ko.mapping
To create a view model via the mapping plugin, replace the creation of
viewModel in the code above with the ko.mapping.fromJS function:
var viewModel = ko.mapping.fromJS(data);
This automatically creates observable properties for each of the
properties on data. Then, every time you receive new data from the
server, you can update all the properties on viewModel in one step by
calling the ko.mapping.fromJS function again:
ko.mapping.fromJS(data, viewModel);
Hopefully this helps.
If your Knockout ViewModel matches your form, you could just use the built in ks.toJSON()
http://knockoutjs.com/documentation/json-data.html
A better option, especially if your form is large or complex, is to use either the mapping or viewmodel plug-ins
http://knockoutjs.com/documentation/plugins-mapping.html
http://coderenaissance.github.io/knockout.viewmodel/
The simplest way to turn your json model into a usable knockout model is with the mapping plugin.
Alternatively, you can manually copy fields from your json model into ko.observable members of your view model, which give you more control and lets you choose to skip read-only properties.

Strange knockout js select option binding issue

Does anybody have a minute to take a look at a puzzling problem I'm having with Knockout JS and binding select lists?
The person's favourite color should be selected in the list by calling value: favColorId in the select list, rather than with the function-based call of value: favColorId(), something very strange is going on here, I've never used () in the past, it's also causing some other weird issues where it won't recall the value into the span (so changing the selected item does nothing).. I have tried recreating a simple sample as best I can demonstrating the issue.
http://jsfiddle.net/goneale/ph8Jw/
I have included my mapDictToArray() function but it simply converts a
javascript object into a key-value JS array. I wouldn't think that is
contributing to the problem.
Actually, that was part of the problem. The function returns a JavaScript array, not an observable array and therefor can't be used properly by Knockout. I've made the following changes to your code:
// The "mapDictToArray" makes a normal JS array, not a ko.observableArray();
// You can't simply "merge" a JS array with an observableArray(); you'll need
// some extra functionality for that: ko.utils.arrayPushAll()
// viewModel.colors(mapDictToArray(dict));
ko.utils.arrayPushAll(viewModel.colors(), mapDictToArray(dict));
// Apply the bindings *after* you've added the contents to the "colors" observable, in order to
// get the correct selected value
ko.applyBindings(viewModel);
That should do the trick (with the correct HTML without the () )!
JSFiddle.
UPDATE
I thought about my solution, but something wasn't correct. The only thing that was correct, was the part that you need to apply the bindings after you've added the contents of the colors observable. This is your fiddle, with that part moved down.
This works in your case, but you'll need to use the arrayPushAll method when there is already data inside the observableArray. This method merges, while you overwrite it when not using it (example with data inside the observable).

Add/remove Knockout observableArray nested elements

I'm trying to add to/remove from a nested observableArray in KnockoutJS. I have an array several elements, each with an attribute object, type object and an attributeValue array which holds objects. So it's a nested array.
The allAttributes array is observableArray. Then I tried making the attributeValue array observable by making a new ViewModel (attributeValueViewModel) with attributeValues as ko.observableArray([]).
I made two Knockout functions (which don't work) and I'm trying to add/remove values to/from that array. The problem is that the array is nested so I have to access the attributeID through this.attribute.id. self.allAttributes[i].attributeValues[j] should be the object I'm adding/removing... where i=attributeID and j=index of the attribute's value object
Why aren't those functions working?
Here is my fiddle: http://jsfiddle.net/M6Hqj/2/
First off, you're overwriting the observable function in your inner view model, e.g. when you assign obj.attribute = item.attribute;, you're overwriting your initial assignment of self.attribute = ko.observable(data.attribute);. Instead assign the value through the observable, like so:
obj.attribute(item.attribute); //instead of obj.attribute = item.attribute;
This will also make your self.addAttributeValue() function call work since the array is now observable.
Next, in your self.removeAttributeValue() function, the this call actually refers to the specific record inside your attributeValues array, therefore, when you do this.attributeValues.splice(), it can't find your attributeValues object property. So, shift the function into the attributeValueViewModel object and use self instead of this, like so:
//This is inside function attributeValueViewModel(data)
self.removeAttributeValue = function() {
alert(JSON.stringify(this));
self.attributeValues.splice(this.id, 1);
}
To call it, just change your data-bind code to use $parent instead of $root, like so:
<button data-bind="click: $parent.removeAttributeValue">REMOVE</button>
Something like this fiddle here: http://jsfiddle.net/UMB79/
(Note that with these changes you still have to modify your logic to correctly add/remove elements, 'cause it's still buggy)

Categories