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
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.
I've got an application which has to show some options inside a select depending on a previous option. To achieve this, I've put the logic to show those options inside a controller function, like this:
vm.getScopeValues = function(tp){
var vals = [];
vals.push({n: 'Opt1', v: 'opt1'});
if(!tp || tp != 'somevalue'){
vals.push({n: 'Opt2', v: 'opt2'});
}
return vals;
};
The problem is that sometimes, I get an undefined as the value of the select options. On the following jsFiddle you can see a simpler approach, but with same result:
https://jsfiddle.net/nr9ffrkk/
As you can see:
If I write track by v, I get undefined
If I write track by o.v, then the values are right, but the ng-model does not get matched correctly
If I write o.v as o.n... without the track by, I get an error ($digest cycles)
When everything gets matched correctly (I achieved it somehow but cannot remember how), if I add a new dynamic "field" (click on "ADD NEW FIELD"), then they come out as undefined values again
I've made console.log to watch the returning values of the function, and it gets called correctly and returns the right values (nothing undefined).
I need to be able to create dinamycally new entries on the fields array (with an initial value for type, of course) and that the select gets the right values for the options.
UPDATED
As you can see, making a controller variable (not a function) with the values does not work neither, bringing the same problem:
https://jsfiddle.net/dgy5ryvh/
Thank you!
I'm working with Angular and part of my page utilizes ng-repeat to display some bug tracker tickets. As part of the site, I also want to provide the ability to search tickets. I'm able to get that part working as I want, and if I'm just appending new tickets they show up fine.
However I would like to be able to, if a user searches, delete all of the currently visible ticket divs and replace them with the search results.
My initial thinking, since I have the ng-repeat set as item in tickets track by item.id, was to just set $scope.tickets equal to the new data. However, this didn't cause Angular to update the DOM.
So, I tried setting $scope.tickets equal to an empty array and then setting it equal to the new data:
$scope.$apply(function() {
$scope.tickets = [];
$scope.tickets = data;
});
Still no update to the DOM, even though console.log($scope.tickets) shows the correct objects.
I'm aware of the method of
$scope.$apply(function() {
array.splice(index, 1);
});
to remove individual elements, but I'm not sure how I would apply that removing all of the elements.
I'll try and get a Plunkr or JSBin added to the Q soon.
What would be the proper way for me to make Angular replace all of the current elements with the new elements created from the data?
try setting array.length = 0
this deletes all elements, while not removing the reference to the array, which actually seems to be the problem in your case.
but another way would be to have a additional data bag.
for example have $scope.data.tickets then you can reasign tickets as usual. important thing is, you have to reference your items using item in data.tickets
Did you test $watch?
$scope.$watch('tickets', function() {
// update data HERE
});
I'm currently making a dynamic-sized editable list component in a form.
I have at least one input field shown which is responsible for the creation of new fields as you type. If you type anything else than a whitespace character, the value of this field is added to the model and then reseted.
On the next tick, Vue updates the view and create the new input field with the letter you typed in, and I give the focus to this field so the user can continue typing as-if nothing happened for him.
So when the field is created, the model gets a new item which has the letter you typed in as its value. The problem is that when you edit the created field, the model isn't updated.
I made a JSFiddle so you can check it by yourself
itemBlured: function (idx) {
console.log(vm.songs[idx].name); // Always print the same letter for a given field
}
The final goal of the itemBlured method is to remove the last edited entry in the model if its value is empty. But for now you can see, by opening your dev console that even if you change the value of a field, the Vue model isn't updated.
Any help or idea is welcome :)
I found the reason why the binding did not occured.
When dealing with <input> tags, you must use the v-model attribute instead of value to tell Vue.js to bind the input to your model, otherwise it just act as mustache template.
Hope it helps someone one day.
I'm trying to get the values of all selected checkboxes with the following code to insert them in a textarea.
$('input[name="user"]:checked').each(function(){
parent.setSelectedGroup($(this).val()+ "\n");
});
but i always get only one value.
How to write the code in a correct way to get the value of ALL selected checkboxes?
Thanks ahead!
EDIT
1) "parent" because the checkboxes are in a fancybox.iframe.
2) setSelectedGroup in the parent window is
function setSelectedGroup(groupText){
$('#users').val(groupText);
You are getting all the values, simply on each loop through the collection you're passing a new value to setSelectedGroup. I assume that method replaces content rather than appending so you are simply not seeing it happen because its too fast.
parent.setSelectedGroup(
//select elements as a jquery matching set
$('[name="user"]:checked')
//get the value of each one and return as an array wrapped in jquery
//the signature of `.map` is callback( (index in the matching set), item)
.map(function(idx, el){ return $(el).val() })
//We're done with jquery, we just want a simple array so remove the jquery wrapper
.toArray()
//so that we can join all the elements in the array around a new line
.join('\n')
);
should do it.
A few other notes:
There's no reason to specify an input selector and a name attribute, usually name attributes are only used with the input/select/textarea series of elements.
I would also avoid writing to the DOM inside of a loop. Besides it being better technique to modify state fewer times, it tends to be worse for performance as the browser will have to do layout calculations on each pass through the loop.
I strongly recommend almost always selecting the parent element for the parts of the page that you're concerned with. And passing it through as the context parameter for jquery selectors. This will help you scope your html changes and not accidentally modify things in other parts of the page.