Angular.js - 来自AJAX请求的数据作为ng-repeat集合

时间:2022-12-02 16:41:10

In my web app i'm reciving data every 3-4 seconds from an AJAX call to API like this:

在我的网络应用程序中,我每隔3-4秒从AJAX调用API返回数据,如下所示:

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

Then displaying the data, like this: http://jsfiddle.net/geUe2/1/

然后显示数据,如下所示:http://jsfiddle.net/geUe2/1/

The problem is that every time i do $scope.invoices = data ng-repeat rebuilds the DOM area which is presented in the jsfiddle, and i lose all <input> values.

问题是,每次我执行$ scope.invoices = data ng-repeat重建jsfiddle中显示的DOM区域,我将丢失所有值。

I've tried to do:

我试过这样做:

  • angular.extend()
  • angular.extend()
  • deep version of jQuery.extend
  • jQuery.extend的深层版本
  • some other merging\extending\deep copying functions
  • 一些其他合并\扩展\深度复制功能

but they can't handle the situation like this:

但他们无法处理这样的情况:

On my client a have [invoice1, invoice2, invoice3] and server sends me [invoice1, invoice3]. So i need invoice2 to be deleted from the view.

在我的客户端上有[invoice1,invoice2,invoice3]和服务器发给我[invoice1,invoice3]。所以我需要从视图中删除invoice2。

What are the ways to solve this problem?

有什么方法可以解决这个问题?

3 个解决方案

#1


1  

Check the ng-repeat docs Angular.js - Data from AJAX request as a ng-repeat collection You could use track by option:

检查ng-repeat文档Angular.js - 来自AJAX请求的数据作为ng-repeat集合您可以使用track by选项:

variable in expression track by tracking_expression – You can also provide an optional tracking function which can be used to associate the objects in the collection with the DOM elements. If no tracking function is specified the ng-repeat associates elements by identity in the collection. It is an error to have more than one tracking function to resolve to the same key. (This would mean that two distinct objects are mapped to the same DOM element, which is not possible.) Filters should be applied to the expression, before specifying a tracking expression.

跟踪表达式中的变量track_expression - 您还可以提供可选的跟踪功能,该功能可用于将集合中的对象与DOM元素相关联。如果未指定跟踪功能,则ng-repeat按集合中的标识关联元素。将多个跟踪功能解析为同一个密钥是错误的。 (这意味着两个不同的对象映射到同一个DOM元素,这是不可能的。)在指定跟踪表达式之前,应将过滤器应用于表达式。

For example: item in items track by item.id is a typical pattern when the items come from the database. In this case the object identity does not matter. Two objects are considered equivalent as long as their id property is same.

例如:item by item中的项目是项目来自数据库时的典型模式。在这种情况下,对象标识无关紧要。只要两个对象的id属性相同,它们就被认为是等价的。

#2


0  

You need to collect data from DOM when an update from the server arrives. Save whatever data is relevant (it could be only the input values) and don't forget to include the identifier for the data object, such as data._id. All of this should be saved in a temporary object such as $scope.oldInvoices.

当服务器的更新到达时,您需要从DOM收集数据。保存任何相关的数据(它可能只是输入值)并且不要忘记包含数据对象的标识符,例如data._id。所有这些都应该保存在一个临时对象中,例如$ scope.oldInvoices。

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

然后在从DOM中收集它之后,使用新数据(您现在正在进行的方式)重新更新DOM $ scope.invoices = data。现在,使用underscore.js _.findWhere来定位你的data._id是否存在于新的数据更新中,如果是这样的话 - 重新分配(你可以在这里使用Angular.extend)你保存到相关的数据值发票。

#3


0  

Came out, that @luacassus 's answer about track by option of ng-repeat directive was very helpful but didn't solve my problem. track by function was adding new invoices coming from server, but some problem with clearing inactive invoices occured. So, this my solution of the problem:

出来了,@ luacassus关于跟踪选项ng-repeat指令的回答非常有帮助,但没有解决我的问题。按功能追踪是添加来自服务器的新发票,但是发生了清除非活动发票的一些问题。所以,这是我对问题的解决方案:

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 app i'm using jQuery's .extend() . There's some good alternative in lo-dash library.

在我的网络应用程序中,我正在使用jQuery的.extend()。在lo-dash库中有一些很好的选择。

#1


1  

Check the ng-repeat docs Angular.js - Data from AJAX request as a ng-repeat collection You could use track by option:

检查ng-repeat文档Angular.js - 来自AJAX请求的数据作为ng-repeat集合您可以使用track by选项:

variable in expression track by tracking_expression – You can also provide an optional tracking function which can be used to associate the objects in the collection with the DOM elements. If no tracking function is specified the ng-repeat associates elements by identity in the collection. It is an error to have more than one tracking function to resolve to the same key. (This would mean that two distinct objects are mapped to the same DOM element, which is not possible.) Filters should be applied to the expression, before specifying a tracking expression.

跟踪表达式中的变量track_expression - 您还可以提供可选的跟踪功能,该功能可用于将集合中的对象与DOM元素相关联。如果未指定跟踪功能,则ng-repeat按集合中的标识关联元素。将多个跟踪功能解析为同一个密钥是错误的。 (这意味着两个不同的对象映射到同一个DOM元素,这是不可能的。)在指定跟踪表达式之前,应将过滤器应用于表达式。

For example: item in items track by item.id is a typical pattern when the items come from the database. In this case the object identity does not matter. Two objects are considered equivalent as long as their id property is same.

例如:item by item中的项目是项目来自数据库时的典型模式。在这种情况下,对象标识无关紧要。只要两个对象的id属性相同,它们就被认为是等价的。

#2


0  

You need to collect data from DOM when an update from the server arrives. Save whatever data is relevant (it could be only the input values) and don't forget to include the identifier for the data object, such as data._id. All of this should be saved in a temporary object such as $scope.oldInvoices.

当服务器的更新到达时,您需要从DOM收集数据。保存任何相关的数据(它可能只是输入值)并且不要忘记包含数据对象的标识符,例如data._id。所有这些都应该保存在一个临时对象中,例如$ scope.oldInvoices。

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

然后在从DOM中收集它之后,使用新数据(您现在正在进行的方式)重新更新DOM $ scope.invoices = data。现在,使用underscore.js _.findWhere来定位你的data._id是否存在于新的数据更新中,如果是这样的话 - 重新分配(你可以在这里使用Angular.extend)你保存到相关的数据值发票。

#3


0  

Came out, that @luacassus 's answer about track by option of ng-repeat directive was very helpful but didn't solve my problem. track by function was adding new invoices coming from server, but some problem with clearing inactive invoices occured. So, this my solution of the problem:

出来了,@ luacassus关于跟踪选项ng-repeat指令的回答非常有帮助,但没有解决我的问题。按功能追踪是添加来自服务器的新发票,但是发生了清除非活动发票的一些问题。所以,这是我对问题的解决方案:

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 app i'm using jQuery's .extend() . There's some good alternative in lo-dash library.

在我的网络应用程序中,我正在使用jQuery的.extend()。在lo-dash库中有一些很好的选择。