AngularJS ng-repeat refresh with new API call
AngularJS ng-repeat refresh with new API call
Currently working on an application where I'm doing an API call to get the data and then using ng-repeat
directive to populate the table on the view.
ng-repeat
<tr md-row ng-repeat="request in requests">
<td md-cell>{{request.name}}</td>
<td md-cell>{{request.email}}</td>
<td md-cell>{{request.application_name}}</td>
<td md-cell>{{request.created_user}}</td>
<td md-cell>{{request.request_type}}</td>
<td md-cell>{{request.status}}</td>
</tr>
And in the controller, a user makes a new request and it adds a row to the database and after the success dialog comes up, I want to make a new request to the API to get the new row that the server generated, so I want to make a new API request.
So, I contact the API and get all the requests again and want to replace the data on the table with the refreshed data from the API
When the API call is successful, it calls this function from the promise:
var onRequests = function(response) {
$scope.requests = ;
response.forEach(function() {
//Processing here and pushing to the new array
});
});
};
But, on creating this new array I'm assuming that the reference to the original array, which the scopes of the ng-repeat pieces have, is lost.
So, I'm trying to get a way for it to just refresh the ng-repeat table with a new array.
Here are things I've tried:
New array and then $apply
ing
$apply
Keeping same array reference and just removing everything and doing
it again, but this seems like a hacky way and I want an elegant
solution
Using $rootScope instead for the array, which seems to work for some
reason...
This is how I did the $rootScope one, which works (but seems hacky):
var onRequests = function(response) {
$rootScope.requests = ;
response.forEach(function() {
//Processing here and pushing to the new array
});
});
};
For some reason this works, and I don't know why it does. That's why I don't understand.
The problem: When I make the api call, this function is called and the $scope.requests
is set to an empty array (does this change the address/lose references?), and then populated with the new data from the API. I am wondering if this doesn't update the ng-repeat child scopes with the new data.
$scope.requests
I know that normally if you change the ng-repeat
$scope
array, it should update the DOM, but since I'm setting it to an empty and new array and then populating that new array, it seems to be losing the reference to the array.
That's why it seems to work if I go and pop every element on the array rather than just setting it equal to a brand new empty array (eg $scope.requests = ;
ng-repeat
$scope
$scope.requests = ;
If anyone could help me out, that would be awesome. I've read around on other questions similar and couldn't seem to find anything helpful or exact along what I'm trying to do, from what I've found, it hasn't worked.
EDIT: Just to be clear, I've read over about a dozen other posts that have similar wording and none were exact to what I am trying to do as I said, so before flagging as duplicate, know that a lot of the other ones didn't work as solutions.
forEach
setTimeout
$timeout
@SatishKumar, just tried that, didn't work :(
– Drew Wilken
Jun 29 at 19:54
Check this Plunker, The idea is same as your issue. Just use
$timeout
.– Satish Kumar
Jun 29 at 20:11
$timeout
I'm not sure I understand your question. If you want to replace the previous data with the new data, both of your examples should work. Do you need to keep a reference to the old data? If so, why?
– Pop-A-Stash
Jun 29 at 21:27
It is not clear why the DOM is not updating. One possibility is that the method that calls the API is not integrated with the AngularJS framework. The $http service which is part of AngularJS framework has no problem when updating with a new reference to an
ng-repeat
.– georgeawg
2 days ago
ng-repeat
1 Answer
1
It sounds like this is your question:
So, I'm trying to get a way for it to just refresh the ng-repeat table
with a new array.
The short answer is this:
$scope.requests = newArrayOfRequests;
Or, what you have works, too:
//clear the array. I don't why you would need a reference to the old array,
// but if you do, then
//$scope.old = requests;
//then
$scope.requests = ;
response.forEach(function() {
// do your processing
$scope.requests.push(processedRow)
});
That's it. In AngularJS, that's all you have to do. That is the magic of AJS binding.
Now, there are some performance improvements that you can make by using track by
in conjuction with your ng-repeat
. But, this is all you have to do to refresh the ng-repeat
.
track by
ng-repeat
ng-repeat
The longer answer has to do with DOM nodes. AJS DOES INDEED keep track of each thing that is added to ngRepeat
using generic ID's that it creates (if you inspect your table in dev tools you can actually see these IDs as attributes). However, this does not help you unless those IDs can be mapped back to your data. Luckilly you can specify that it use a unique ID from the actual data using track by
:
ngRepeat
track by
<tr md-row ng-repeat="request in requests track by request.some_unique_id">
<td md-cell>{{request.name}}</td>
<td md-cell>{{request.email}}</td>
<td md-cell>{{request.application_name}}</td>
<td md-cell>{{request.created_user}}</td>
<td md-cell>{{request.request_type}}</td>
<td md-cell>{{request.status}}</td>
</tr>
What this does is allows AJS to re-use DOM nodes that it previously created from the first time the data was loaded instead of recreating them each time you load new data.
When you load the new array, AJS only has to update the value of each row, or in your case, it only has to add a single DOM node for the new row that is returned by the API
But that doesn't change how the data is refreshed. Simply assign a new array to the $scope
variable, or clear it and push new data. That's all there is to it.
$scope
This is exactly what I'm trying to do yes! But, for some reason, when I do load this new array into the $scope array that ng-repeat uses, it doesn't update the DOM. I was thinking maybe the child scopes that ng-repeat creates don't have a reference to the new array because the new array is created just by $scope.requests = and then populating it? When I do what you suggested, it doesn't seem to update the Dom, but does update the array correctly. Thanks for the in depth reply! What do you think would be a correct way to format this?
– Drew Wilken
2 days ago
Also, just to be clear, I don't need a reference to the old array, sorry if I came across like that. I literally just want the table to repopulate the data with the new API call, but when I set
$scope.requests = ;
I am concerned that the scopes created on the ng-repeat rows lose the reference because now $scope.requests points at the new array rather than the one that populated the table. that is why it works if I pop every element off the array rather than setting it equal to a brand new array. So, with that being said, what's a good way to go about the problem?– Drew Wilken
2 days ago
$scope.requests = ;
Ok, that makes sense. If you are not seeing the data in the table update, then you may have a deeper problem that we can't see from your code.@georgeawg is right
– Pop-A-Stash
21 hours ago
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Try putting
forEach
inside a timeout, either asetTimeout
or$timeout
of 0 seconds, to make changes in the next digest cycle.– Satish Kumar
Jun 29 at 19:47