I receive an object which is on server-side a map, i.e. a key-value array. I would like to bind it in an Angular form and be able to modify the value (easy) and the key. Challenge is that when the key is modified, the associated value has to stay linked.
I tried :
<div ng-repeat="(type, value) in estate.extraServices track by $index">
<input ng-model="type"> <input ng-model="estate.extraServices[type]">
</div>
But when the first input change, a new line is added to the map and the new one is not linked to the new one.
My goal is to avoid using a scope function to resolve this problem, so I ask without many hope, but who knows !
If a binding on a key isn't possible, I would probably change the object structure to an array of Pair object (2 property : key and value)
<div ng-repeat="pair in array">
<input ng-model="pair.key"> <input ng-model="pair.value">
</div>
You can't bind an input to the actual property name. Object property names can't be changed dynamically
Your first example however works fine to update values
<div ng-repeat="(type, value) in estate.extraServices track by $index">
{{type}} <input ng-model="estate.extraServices[type]">
</div>
As for adding keys you would need to use a different input not bound to that object to add a new key to the object. Then with an event handler use a function that updates the object
Same for removing keys , use an event handler function that would do delete object[key]
Changing to an array of objects with same key name structure would likely be simplest depending on how this object is used
DEMO
Related
I am having nested objects with multiple properties. I have created an input field on the UI for every property and value is changed by using [(ngModel)]. I want to implement a functionality where if any value in the object is changed I should be able to detect it and enable the reset option to show initial values again.
I have tried exploring this and the majority of answers were related to form controls only.
if you bind with two-way binding to data you will not be able to hold old record. You can write a fn to compare to objects if you bind with [ngModel].Here is pseudo.
in .ts
value = {}
onValueChange(data:any){
const changedData = getChangedData(this.value, data);
}
in .html
<input [ngModel]="value" (ngModelChange)="onValueChange($event)">
}
i wants to modify and object within an array without altering the original array as
in the original array looks like:
books:Book[] = [{author:"John Doe",title:"Javascript"},{author:"John Doe",title:"Javascript"}]
selectedBook:Book = Books[1];
within HTML template, i have:
<input [(ngModel)]=selectedBook.name/>
<table>
<tr *ngFor = "let book of books">
<td>{{book.name}}</td>
</tr>
</table>
now whenever the value of the input changes it's reflects on both the 'selectedBook' and the object within the array thus, changes the table value as well event though the input value is binds to copied object which is 'selectedBook', so how do i modify the object at position 1 in the array without modifying the original object in the array
You can use Object.assign() to clone an object.By using it changes made to the cloned object will not get reflected to the original object in the books array
books:Book[] = [{author:"John Doe",title:"Javascript"},{author:"John Doe",title:"Javascript"}]
selectedBook:Book = Object.assign({},Books[1]);
For more info about Object.assign() read the link below
https://googlechrome.github.io/samples/object-assign-es6/
I have a <select> with ng-options defined by an object. ng-model captures the selcted object, but I want to also capture the key that was selected. I haven't been able to find a way to do that. Here's an html snippet.
<select class="form-control" id="xaxis" ng-model="model.xaxis" ng-options="k for (k,v) in model.options"></select>
Here's an example of the model.options object:
$scope.model.options = {
"power":{"label":"blah","values":[],"color":"red"},
"voltage":{"label":"blah","values":[],"color":"blue"}
}
If I select "power", my ng-model variable becomes {"label":"blah","values":[],"color":"red"}. I want to also capture, the key "power" as a scope variable. How would one do that?
You can use the key values instead, that way you can easily access data in your controller using $scope.model.options[$scope.model.xaxis].
I've got a bunch of text boxes that are supposed to hold the value for a number of separate elements in an observableArray. The number of text boxes depends on how many "properties" a user selects on an earlier screen, and the properties can be added and removed at will later on. Currently, I'm starting with an empty array and attempting to set the value binding of the textbox as a new key in the array:
<input type="text" class="tdEdit" data-bind="value: listing.properties[property_id]"/>
Listing is an object that has var properties = ko.observableArray([]) defined in it. My goal is to have properties array look something like {"property1": "3", "property2": "4"}, etc. Currently, though, the properties array always remains empty.
Hopefully that makes some sort of sense.
Use properties()[property_id] instead of properties[property_id]
data-bind="value: listing.properties()[property_id]"
I think listing.properties should be a ko.observable instead of ko.observableArray
JSFiddle DEMO
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.