Angular.js - data from an AJAX request as an ng-repeat collection

In my web application, I get data every 3-4 seconds from an AJAX call in the API as follows:

$http.get('api/invoice/collecting').success(function(data) { $scope.invoices = data } 

Then display the data as follows: http://jsfiddle.net/geUe2/1/

The problem is that every time I do $scope.invoices = data ng-repeat, the DOM region that is represented in jsfiddle is restored, and I lose all <input> values.

I have tried:

  • angular.extend()
  • deep version of jQuery.extend
  • some other merge \ extension \ deep copy features

but they cannot handle this situation:

My client has [invoice1, invoice2, invoice3] , and the server sends me [invoice1, invoice3] . Therefore, I need invoice2 to be removed from the view.

What are the ways to solve this problem?

+4
source share
3 answers

It turned out that the @luacassus answer about the track by option of the ng-repeat directive was very useful, but did not solve my problem. The track by function was to add new invoices coming from the server, but there was a problem clearing inactive invoices. So this is my solution to the problem:

 function change(scope, newData) { if (!scope.invoices) { scope.invoices = []; jQuery.extend(true, scope.invoices, newData) } // Search and update from server invoices that are presented in scope.invoices for( var i = 0; i < scope.invoices.length; i++){ var isInvoiceFound = false; for( var j = 0; j < newData.length; j++) { if( scope.invoices[i] && scope.invoices[i].id && scope.invoices[i].id == newData[j].id ) { isInvoiceFound = true; jQuery.extend(true, scope.invoices[i], newData[j]) } } if( !isInvoiceFound ) scope.invoices.splice(i, 1); } // Search and add invoices that came form server, but are nor presented in scope.invoices for( var j = 0; j < newData.length; j++){ var isInvoiceFound = false; for( var i = 0; i < scope.invoices.length; i++) { if( scope.invoices[i] && scope.invoices[i].id && scope.invoices[i].id == newData[j].id ) { isInvoiceFound = true; } } if( !isInvoiceFound ) scope.invoices.push(newData[j]); } } 

In my web application, I am using jQuery .extend() . There is a good alternative in the lo-dash library.

0
source

Check ng-repeat docs Angular.js - data from an AJAX request as a collection of ng-repeat You can use the track by option:

in the track of the expression track_expression - you can also provide an additional tracking function that can be used to associate objects in the collection with DOM elements. If no tracking function is specified, ng-repeat binds items by ID in the collection. The error is that you can use several tracking functions for the same key. (This would mean that two different objects are mapped to the same DOM element, which is not possible). Filters must be applied to an expression before specifying a tracking expression.

For example: an item in the item track item.id is a typical pattern when items come from the database. In this case, the identifier of the object does not matter. Two objects are considered equivalent if their id property is the same.

+1
source

You need to collect data from the DOM when an update arrives from the server. Save any data (it can be only input values) and do not forget to include the identifier of the data object, for example data._id . All of this should be stored in a temporary object such as $scope.oldInvoices .

Then, compiling it from the DOM, re-update the DOM with the new data (as you are doing right now) $scope.invoices = data . Now use underscore.js _.findWhere to find if your data._id is present in the new data update, and if so, assign (you can use Angular.extend here) the value that you saved in the corresponding invoice.

0
source

Source: https://habr.com/ru/post/1499790/


All Articles