I have a collection of objects in my view model. I'm experiencing an issue when binding a value to select control. The value is a JS object and not a primitive type. When I have more than one object in the bound collection and change the select control, all of the other object's values update to the newly selected one. It's like all of the values are bound to the same instance inside the foreach binding. The error only seems to happen when new rows are inserted, not when simply editing existing ones.
I have striped out a lot of the complexities and have an example showing the issue on JSFiddle.
http://jsfiddle.net/zero21xxx/5vgDy/
Steps to see the Error
Select Settle Type from the drop down of row 1
Select "Two" from the new drop down to the right.
Select Settle Type from the drop down of row 2
Both row 1 and row 2 will now both be set to "One" in the select box.
I would expect that a change in one row would not effect any of the other rows.
It's all a bit complicated how you have it setup, however, I think the problem is, that your ids are not what you expect,
function getValues(tabId) {
console.log("tabId " + tabId);
if (lookUp[tabId]) {
if I add that to your code, it show's the same tabId, which means you are dealing with the same objects by the looks of it.
if I change getValues so each time it does
function getValues(tabId) {
console.log("tabId " + tabId);
return [new DatabaseField(nextId(), "Name", "Attorney Name", DataType.STRING.id),
new DatabaseField(nextId(),
"Type", "Settle Type", DataType.DROPDOWN.id)];
}
also I changed all the observables with [] to observable arrays...
then it seems to work. fiddle... http://jsfiddle.net/keith_nicholas/wmxJX/
Each time that you choose a different selectedDatabaseField it rebuilds the availableOptions.options. Each of the rows are bound against these same options as choices. When the options are rebuilt, then each row's selected value is no longer a valid choice.
Even if the object looks exactly the same it is not equal unless it is a reference to the same object.
So, since the options have changed and the currently selected value is no longer valid, the value binding will assign the first option as the value (unless you have an optionsCaption specified).
So, you probably don't want to rebuild the options, if they are already built or you would want separate options for each row rather than binding against the same database field object.
Related
I have seen a similar question, but in my case it doesn't work.
I have a JSON model, called data, which corresponds to a SAPUi5 form with comboboxes. I want to copy the state of the model the first time I open my application and keep it like that. After that I want to use it to reset my form and bring the comboboxes back to their default values.
When I first start my application:
this.getView().setModel(new JSONModel(data)); //create the original model
//copy the original model (copyModel is global variable
copyModel = $.extend({}, data);
Until here everything is fine. The two models are exactly the same. After that I have a button and a reset Function:
resetP: function(){
this.getView().setModel(new JSONModel(copyModel));
console.log(copyModel);
}
The first time I select something in the comboboxes and click the reset button and run the reset function, the copymodel is the right one. Same with the original data model. When I change again the selected value of the combobx, the copyModel, starts taking the selected value. Somehow it's overwritten. I don't know what I am doing wrong. Are there any suggestions? I have also tried to use JSON.strignify instead of extend.
JSON models be default have two way binding. So when you are triggering events like selectionChange on the ComboBox, because of two way binding, the set data to the model keeps getting updated. Also Javascript has objects by reference, so it is the original copyModel object that gets updated.
You can prevent this by setting a copy of the copyModel to the JSON model.
Another thing I would like to mention is that do not keep setting the model again and again.
You can just update the data that is set to the model and update the model.
This can be done in 2 ways.
a.
resetP: function(){
this.getView().getModel().setData(copyModel);
console.log(copyModel);
}
b. You could also update the required property and do a
this.getView().getModel().updateBindings();
We use jQuery.extend(true, {}, object_to_copy); in this way to create a "deep copy" from the object we want an independed copy from.
In the editOptions for select dropdown we pass some static values after the instantiate of the grid_data. Everything works fine until we choose editing. As the data remains constant and static.
All the dropdown remains same. But this should not happen, it has to load the appropriate data to the rows which should be dynamic.
var data = {
"id" : "cityGrid",
"grid_data" : response,
"colNames" : ['City Name','Select State','local'],
"colModel": [
{"name":'cityName',"index":'cityName', "width":150,"editable": true,"editoptions":{"size":"20","maxlength":"30"}},
{"name":'selectState',"index":'selectState',"width":90,"editable": true,"edittype":"select","editoptions":{"value":"TN:Tamilnadu;AP:Andhrapradesh;MP:MAdhyapradesh",
"class":"chosen-select","width":200,"custom":true,"custom_func":util.applyChosen}},
{"name":'local',"index":'local', "width":70, "editable": true,"edittype":"checkbox","editoptions": {"value":"Yes:No"},"unformat": "aceSwitch"}
],
"editurl": "/dummy.html",
"caption": "City Information"
};
"editoptions":{"value":"TN:Tamilnadu;AP:Andhrapradesh;MP:MAdhyapradesh"
I also came across dataUrl passing after few search results. But it was not upto the mark as i need to send a param with it which is not possible there.
And even thought of taking the value of one particular row data and make it select on top and load rest of with static as i use the chosen form of data which triggers on keypress and my problem would get solve. The problem here is with editing with two types one with single row and multirow.
This is a phase where i got struck. Has anybody solved this problem. Any new version of jQgrid has a answer to this problem?
Thanks in advance
First of all you do can generate dataUrl dynamically based. The easiest way would be to define dataUrl as callback function: dataUrl: function (rowid, value, name) { ... }.
On the other side it seems that you need to generate select with <option> where value is not the same as the displayed text: <option value="TN">Tamilnadu</option>. In the case the value TN will be saved in the column after editing and so you should probably hold (to fill) the corresponding column with data like TN, AP, MP instead of Tamilnadu, Andhrapradesh, MAdhyapradesh. You should use formatter: "select" (see here) to display input values TN, AP, MP like Tamilnadu, Andhrapradesh, MAdhyapradesh. The formatter formatter: "select" uses formatoptions.value or (it it's not defined) the editoptions.value value. So one have to be able to set editoptions.value (or formatoptions.value or both) before the grid content will be created, so before the server response will be processed by jqGrid.
To be able to set the editoptions.value dynamically one can use setColProp method. If you loads the data from the server one can include all column property with exception name property in the server response. One can do this inside of beforeProcessing callback for example. The answer this one and this one describe the approach detailed. The answer shows how one can use common column name property ("c1", "c2", "c2") and uses jsonmap to read the relatively common named data. One can set jsonmap instead of name property if it's needed.
I'm using ngList within an text box to get and post data to my server. The issue I've found is that while I can directly affect the generated array by removing indexes, when removing an item this way, the string in the input field is left unaffected.
The problem here is that as soon as the text field is modified, whatever is contained in that field immediately updates the model, restoring whatever items were removed.
http://plnkr.co/edit/EqkWwyLwvHrrhT6epOYP?p=preview
Does anyone have a solution for updating the string within the text field to match the model as the model is updated? My thought was to use an $apply either on my function or within a $watch but in both cases I got $apply in progress errors.
$scope.states.splice(index, 1);
It will not update ng-list because the change mechanism only invoked if previous value is not equal current value strictly...
So if you will create new instance instead of the splice current one nothing will be invoked because it is the same array instance so replace this code with the current one and it will be what you want...
var tmpList = angular.copy($scope.states);
tmpList.splice(index, 1);
$scope.states = tmpList;
and here is PLUNKER
I have a global controller in my AngularJS application which provides me with a array containing Attendee objects. Want i want is to modify my CourseRegistration Model which contains one specific attendee object. In the edit window I d like to get a dropdown with all possible attendees whereas there should be the current attendee selected.
I have the following code in my html:
<select ng-model="courseRegistration.attendee" ng-options="attendeeSelectItem.name for attendeeSelectItem in attendeeSelectItems"></select>
If I print out courseRegistration.attendee with JSON.stringify and do the same with the corresponding option they print out the same object (same id, same name etc.). But if I do something like (courseRegistration.attendee == attendeeSelectItem) for the two identical objects, then I get false.
So my question is how can I make sure that the currently selected item (stored in courseRegistration.attendee) gets matched with the corresponding object in my list (which is used by options) ?
Thanks a lot in advance.
JSFiddle: http://jsfiddle.net/2ddCy/
Greets
Marc
Essentially when you use an array of objects to populate a select, it selects the entire object, not just the one item you're seeing in the select list.
See this question for detail and example code: Problems when using ng-options and ng-switch together
I'm assuming that you've got something like the following in your controller?
$scope.courseRegistration = {attendee: {id: 2, name: "A Person"}}
If so, the reason the comparison fails is that although the object may have the same properties as the one currently selected, it refers to a different object in memory and therefore isn't classed as equal.
Now as a quick hack you could stringify them and then compare, however the correct approach would be either to set the current value by key:
$scope.courseRegistration = {attendee: attendeeSelectItems[1]};
Or just store the id/name and set your ng-options condition to bind to just that value:
$scope.courseRegistration = {attendee: 1};
<select ng-model="courseRegistration.attendee" ng-options="attendeeSelectItem.id as attendeeSelectItem.name for attendeeSelectItem in attendeeSelectItems"></select>
Consider this jsfiddle.
I can't think of a way to ensure that if row one in the above example has already been selected in the dropdown that the next row would be prevented from selecting the same value.
I think that my problem here is that when the dropdown click event fires, the subscriber does not monitor this change when the child value has changed. Anyone able to assist?
viewModel.actualMetrics.subscribe(function(newValue) {
if (newValue) {
$.each(viewModel.actualMetrics(), function(n, item) {
if (item.MetricTypeId() == newValue.MetricTypeId)
alert("already selected this Metric");
});
}
Here is a basic sample of one way to do what you want: http://jsfiddle.net/rniemeyer/3cpUp/
Here is your sample with it: http://jsfiddle.net/rniemeyer/8bQmq/
The basic idea is that you have your list of choices, then you create a dependentObservable that is an index of the currently used choices. This saves some looping through the current choices when building each rows options. This index could be an object or an array. I used an object, but you could use an array as well with the id as the index.
Then, on each item, you could have a dependentObservable to store the filtered choices for that item. However, I used a function instead, because it does not seem like a property that is really important to the view model and bindings are implemented using dependentObservables, so you get the same effect without having the choices show up when you send it toJSON. The function loops through all of the choices and includes only the choices that do not appear on another line by checking its own value and the index.