Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
216 views
in Technique[技术] by (71.8m points)

javascript - AngularJS: ng-repeat with dynamic list, without rebuilding entire DOM tree?

I'm using ng-repeat on a table row with data from a JSON array retrieved from a server. My goal is to have the list update automatically whenever an item is added, removed, or modified on the server, without affecting the unmodified items. In the final implementation, these table rows will also contain bidirectionally bound <input> and <select> elements to send updates back to the server. Some of the available options in the <select> elements will also be generated using ng-repeat directives from another list that may also change.

So far, every time a new array comes from the server (currently polled every two seconds), the entire ng-repeat list is deleted and regenerated. This is problematic because it interferes with text selection, destroys input fields even if they are currently being edited by the user, and probably runs a lot more slowly than necessary.

I've written other web apps that do what I want using jQuery and DOM manipulation, but the code ends up being really hairy and development is time consuming. I'm hoping to use AngularJS and data binding to accomplish this in a fraction of the code and time.

So here's the question: is it possible to update the backing array this way, but only modify the DOM elements corresponding to the items/properties that actually changed?


Here's a minimal test case that simulates periodic polling using a hard-coded array in a timer (see it live at http://jsfiddle.net/DWrmP/). Notice that the text selection is cleared every 500ms due to the elements being deleted and recreated.

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);
        }
        ]
);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For those finding this from google, the page below describes a feature in AngularJS 1.2 that helps with this problem:

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


Edit to add: The most important sentences from the linked post, in case the link ever dies:

With the new "track by" syntax, I can now tell AngularJS which object property (or property path) should be used to associate a JavaScript object with a DOM node. This means that I can swap out JavaScript objects without destroying DOM nodes so long as the "track by" association still works.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...