【问题标题】:AngularJS: ng-repeat with dynamic list, without rebuilding entire DOM tree?AngularJS:带有动态列表的 ng-repeat,而不重建整个 DOM 树?
【发布时间】:2013-06-09 09:27:47
【问题描述】:

我在表行上使用 ng-repeat,其中数据来自从服务器检索的 JSON 数组。我的目标是在服务器上添加、删除或修改项目时自动更新列表,而不会影响未修改的项目。在最终实现中,这些表行还将包含双向绑定的<input> 和<select> 元素,以将更新发送回服务器。 <select> 元素中的一些可用选项也将使用另一个列表中的 ng-repeat 指令生成,这些指令也可能发生变化。

到目前为止,每次从服务器传来一个新数组(目前每两秒轮询一次),整个 ng-repeat 列表都会被删除并重新生成。这是有问题的,因为它会干扰文本选择,破坏输入字段,即使它们当前正在由用户编辑,并且可能运行得比需要的慢得多。

我已经编写了其他 Web 应用程序,它们使用 jQuery 和 DOM 操作来执行我想要的操作,但是代码最终变得非常繁琐,并且开发非常耗时。我希望使用 AngularJS 和数据绑定在一小部分代码和时间内完成这项工作。

那么问题来了:是否可以通过这种方式更新后备数组,但只修改与实际更改的项目/属性相对应的 DOM 元素?


这是一个最小的测试用例,它使用计时器中的硬编码数组模拟定期轮询(在http://jsfiddle.net/DWrmP/ 上查看它的直播)。请注意,由于元素被删除和重新创建,因此每 500 毫秒清除一次文本选择。

HTML

<body ng-app="myApp">
    <table ng-controller="MyController">
        <tr ng-repeat="item in items | orderBy:'id'">
            <td>{{item.id}}</td>
            <td>{{item.data}}</td>
        </tr>
    </table>
</body>

JavaScript

angular.module('myApp', []).controller(
    'MyController', [
        '$scope', '$timeout',
        function($scope, $timeout) {
            $scope.items = [
                { id: 0, data: 'Zero' }
            ];

            function setData() {
                $scope.items = [
                    { id: 1, data: 'One' },
                    { id: 2, data: 'Two' },
                    { id: 5, data: 'Five' },
                    { id: 4, data: 'Four' },
                    { id: 3, data: 'Three' }
                    ];
                $timeout(setData, 500);
            }
            $timeout(setData, 500);
        }
        ]
);

【问题讨论】:

  • 感谢您的提问。有同样的问题,很容易与你的问题联系起来并理解答案

标签: javascript angularjs angularjs-ng-repeat


【解决方案1】:

我计划最终自己构建以下解决方案,尽管它仍在我的产品积压中。

ng-repeat 的问题是它会在需要时从 DOM 中删除项目,因此对于表来说,这意味着它会调整大小等,但如果数据是动态的,它可能会闪烁,因为数据发生了变化并且桌子的大小正在发生变化。特别是在分页期间,因为整个页面可能尚未加载。

要避免这种闪烁,表格不得更改其行数。取而代之的是“显示”数据的 ng-repeat,只需根据需要更改它,而无需从数组中添加或删除项目。

【讨论】:

    【解决方案2】:

    对于那些从谷歌上找到这个的人,下面的页面描述了 AngularJS 1.2 中有助于解决这个问题的功能:

    http://www.bennadel.com/blog/2556-Using-Track-By-With-ngRepeat-In-AngularJS-1-2.htm


    编辑添加:链接帖子中最重要的句子,以防链接失效:

    使用新的“track by”语法,我现在可以告诉 AngularJS 应该使用哪个对象属性(或属性路径)来将 JavaScript 对象与 DOM 节点相关联。这意味着只要“track by”关联仍然有效,我就可以在不破坏 DOM 节点的情况下交换 JavaScript 对象。

    【讨论】:

    • 虽然链接提供信息,但链接最终会失效——添加基本部分会更好。
    • 只有在加载了整个集合时才有效,如果卸载了集合的一部分,您仍然会遇到问题。
    • Link 还提供了一种智能的方式来调试和记录您的 DOM 信息。谢谢!我真的很喜欢这个人——本纳德。他的大部分文章都非常有帮助。
    【解决方案3】:

    我相信这篇文章将解释 ngRepeat 的工作原理

    http://www.bennadel.com/blog/2443-Rendering-DOM-Elements-With-ngRepeat-In-AngularJS.htm

    因此,如果您将对象保存在集合中 - 那么是的(即 $hashKey 持久)

    否则 - 否

    【讨论】:

    • 在问这个问题之前我已经看到了那个页面。虽然 $hashKey 的解释很有帮助,但仍然不清楚如何确保深度嵌套对象上的单个属性更改将导致相应组件被更新,而无需重建整个 ng-repeat 部分。 -- 我尝试使用angular.extend() 和jQuery.extend(true),但这并没有达到预期的效果,这意味着我必须手动管理添加/删除。 -- 我希望 AngularJS 保留一份它可以用来跟踪更改的列表的内部副本;看来我得自己动手了。
    • @nitrogen 你能添加 Angular 不为你跟踪的更改示例代码吗?
    • 你的示例代码不仅会重新创建列表项,还会重新创建列表本身,每 500 毫秒,所以 Angular 不能在这里做任何事情,你只会不断地重新渲染页面。
    • 示例代码的目的是模拟从 JSON 解析数组,每次都会创建一个新数组。一旦我弄清楚我的新方法的效果如何(将中间副本存储在对象中,然后在添加或删除项目时将其排序到数组中),我将更新问题或使用更好的示例发布答案。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-07
    • 1970-01-01
    • 2017-03-24
    • 1970-01-01
    • 2013-08-11
    • 1970-01-01
    相关资源
    最近更新 更多