So, the issue I'm having is I have an array in my controller $scope called $scope.calls and I can push in to that array just fine and have it update on the page. Simple stuff. What I want to do is to be able to delete from $scope.calls and have it reflect on the page like that. If you look at $scope.deleteCall(), it deletes it from the array fine but doesn't remove the elements from the page. Is there away to clear out those elements when the data is removed?
http://jsfiddle.net/kyct/6tcW8/75/
The problem was that you were not removing the item from an array really. The correct approach would be:
$scope.deleteCall = function (callIndex) {
$scope.calls.splice(callIndex, 1);
}
Here is a working jsFiddle: http://jsfiddle.net/UAPhn/
Related
please help me how to change my code to be able to filter an array based on drop down selection, then deleting a field from an array.
Code is uploaded here: http://jsfiddle.net/x8e3rvcj
It works if I select first and second list item but returms empty array after third/fourth selection, seems because of deleting a field in the result array.
If I remove the deletion part the selection works properly.
Deletion part seems causing issue is:
finalArray = jQuery.each(finalArray, function(arrElem, arrValue) {
Delete arrValue.MID;
});
Thanks
After a day searching what I found is that copying / editing arrays in javascript impacts any copy of the array in scope.
This is called mutating.
Solution: don't simply copy an array but "deep" copy it:
let copyArray = JSON.parse(JSON.stringify(valueArr)); //... etc.
Thanks whoever invented this annoying concept for my extra time spent on this code part!
I am working on a new Angular Application and I am building a dropdown navigation. I am currently using a Factory to return the array of nav items within the controller like so:
var sections = this.NavMenusFactory.sections;
The structure of the menu looks like so:
I need to cycle through the array and remove any items that the user does not have permissions to access but also retain the original structure. This is dictated by the current user and the requiredPermissions index within the array objects.
I have access to the lodash library so have been playing around with this by trying out filter and remove functions. Nothing is working exactly how I need it. To give a quick example of how I am trying to do it:
var sections = this.NavMenusFactory.sections;
this.dropdownNavItems = [];
forEach(sections, (section) => {
if (section.section === 'financials') {
this.dropdownNavItems = this.dropdownNavItems.concat(section.pages.filter(navitem => {
// console.log("section", navitem);
return !navitem.requiredPermissions || this.Permissions.parseAccessByValue(selectedVehicle, navitem.requiredPermissions);
}));
}
});
I'm not able to retain the original structure like in the image just with the items removed. I am very new to Javascript so some guidance would be much appreciated.
Your code looks correct to me, and I would suggest that your issue is actually more likely an angular related one.
Assuming you are using ng-repeat to iterate over all the results, chances are that your issue involves the 'track by' part of ng-repeat. Please see this part of the ng-repeat docs You could try using track by item.name or something similar, see if that solves your problems.
The problem that I'm facing is that I have a ng-repeat and when I delete an item by clicking a button with a function associated to delete items in array the ng-repeat not shows properly the actual array.
The array looks like:
['stuff', 'stuff', 'stuff', ....]
What shows ng-repeat when I delete an item is the array without the last position although I deleted the first position. When I perform a console.log the array looks correct, the first position or x position was removed.
The problem was the:
track by $index
Due to some duplicate images in the proofs I've been doing. I removed it and it works as expected.
I was having this issue, I eventually narrowed it down to having something to do with the angular not being notified that something changed. To work around this, try using $apply. So something like this:
$rootScope.$apply(function() {
// remove the item from the array
})
long answer: https://github.com/angular/angular.js/wiki/Understanding-Scopes
short answer, switch your array to be:
[{label:'stuff'},...]
I am trying to update ng-grid with array splice.
I have a plunk here.
Add button adds new row. Update button updates last item in the array.
Select a row & press update button. Nothing happens.
Press add button. Now UI gets updated with new element & as well as the previously updated element.
Same behavior gets repeated again & again.
I tried $scope.$apply. I get:
“Error: $apply already in progress”
I even tried by placing $scope.$apply block inside a setTimeout call. Again the same error!
Any pointers!
Thanks!
That's because data $watcher in ng-grid (incorrectly) compares the data object for reference, instead on object equality. You might remedy this by setting the third parameter to true in data $watch function (line 3128):
$scope.$parent.$watch(options.data, dataWatcher, true);
Plunker
UPDATE (2015-04-10)
Angular has improved their code base (1.4.0), try the $scope.$watchCollection method first, and see if it works for you. (Link)
ANSWER
If you don't feel like hacking into a 3rd party library, you could add the hack in your code using:
$scope.updateData = function() {
var data = angular.copy($scope.myData);
data.splice(data.length - 1, 1, {name: 'UPDATED', age: '4'})
$scope.myData = data;
};
plunkr
As #Stewie mentions, the problem is that for performance reasons ngGrid compares the data object superficially, and in the case of arrays, this is by reference. ngGrid also compares by the array length, so if the array doesn't change it's length the grid wont' get updated.
This solution creates a copy of the array (different place in memory) so that when angularjs $watcher checks for changes it will find a different object and run the ngGrid update callback.
NOTE: Because this solution creates a copy of the data array on every call to updateData, it could lead to performance problems if your data is too big, also Javascript doesn't have a great garbage collection.
Old Incorrect Answer:
$timeout(angular.noop, 0);
This simply sets a timeout to trigger a $scope.$apply() after the current one is done. A way of forcing a dirty check.
I am using ui-grid v3.0.0 (from an April 2015 unstable build). I found this post and wanted to show others how I refreshed my grid after I removed a row from the grid data object using splice:
// Remove the row and refresh the grid.
$scope.myData.splice(rowIndex, 1);
$scope.gridApi.grid.refresh(true);
where my gridApi scope variable was set with this function:
$scope.gridOptions.onRegisterApi = function(gridApi){
$scope.gridApi = gridApi;
}
I have a JSON array coming from a REST API. I am using the Knockout mapping plugin to process the array and load the JSON into preset form values (if a user has added values to the form previously - I have data there to test the Knockout arrays). The form essentially adds or deletes div blocks with inputs so users can add/delete "work" experiences.
My trouble is with trying to decipher how the plugin maps the arrays. I am trying to locate a specific value (the id) of a row in the array so I can add it as a variable to tell the API to delete that specific row. I can get Knockout to explicitly output the row value in the html, but I can't figure out how to capture it otherwise. In the template "foreach" I have a button that references a "remove:" and that's where I'm stuck in trying to capture the value from the array.
For Example in the HTML:
This outputs the two rows of the "work" object no problem:
<span data-bind="text: ko.mapping.toJSON(workModel.work())"></span>
[{"id":"1","schoolID":"2","place":"","position":"Science Teacher","description":"I worked at ASD for 1 year as a Science teacher.","start":"2011","end":"2012","profileID":"91"},{"id":"2","schoolID":"1","place":"American School of Taiwan","position":"Science Guy","description":"I was just another science guy","start":"2008","end":"2011","profileID":"91"}]
This outputs the id of the first row and item in the array:
<span data-bind="text: ko.mapping.toJSON(workModel.work()[0].id)"></span>
"1"
But in the javascript, if you click on the remove button generated by the foreach template...
gone = function(work) {
alert(ko.mapping.toJSON(workModel.work(this).id));
}
Gives me this error in Firebug, and then the UI reloads and drops out the template block I just clicked on.
Unable to parse bindings. Message: TypeError: workModel.work()[0] is undefined; Bindings value: text: ko.mapping.toJSON(workModel.work()[0].id)
Even though, if I replace the above alert with the explicit statement:
gone = function(work) {
alert(ko.mapping.toJSON(workModel.work()[0].id));
}
I get the correct value of "1" again. I know it has to do with the "this" aspect of the code, but I'm not sure what the mapping plugin is doing so that I can capture the specific value from the array...make sense? Any help would be greatly appreciated.
I'm going out on a limb here, but I do think it's the this-problem yes. Scoping in Javascript can be a hassle sometimes. Try doing something like this in the scope containing the gone-function:
var self = this;
gone = function(work) {
alert(ko.mapping.toJSON(workModel.work(self).id));
}
Disclaimer: I'm not able to test this myself right now, but give it a try :)
I finally got it. It came from combining different post on Stack Overflow and also from the Knockout forums. I'm sure other folks have more elegant solutions than this, but it works for me.
In the foreach loop on the "Delete" (or whatever button you want to use to capture the value) button I included the following on the data-bind:
Remove
Then in the javascript I have:
var self = this;
var row_id;
self.remove = function(index){
var row_id = index;
alert(row_id);
}
The alert returns the row ID of the loaded JSON as I wanted. The $data.id() could be changed/used to return any mapped element from the loaded JSON. The row_id is then a global that can be accessed elsewhere as well.