2016-12-13 23 views
10

Cho một mảng sourceArray Tôi muốn tạo một targetArray phụ thuộc vào các mục nhập đầu tiên. Điều này có nghĩa là Mảng được tạo nên chứa một mục nhập cho mỗi mục nhập nguồn và được cập nhật bất cứ khi nào thay đổi sourceArray. Tuy nhiên việc sửa đổi targetArray sẽ không bao giờ cập nhật nguồn.AngularJS: Databinding giữa các mảng

Điều này Plunker loại tác phẩm miễn là sourceArray là tĩnh. Ngay sau khi bạn bắt đầu sửa đổi các mục nguồn, nó rõ ràng sẽ không cập nhật đúng mục tiêu vì tôi thiếu một cơ chế dữ liệu thích hợp.

Tôi có cần cập nhật targetArray theo cách thủ công bằng cách quan sát sourceArray hoặc có bất kỳ loại cơ chế 1 chiều nào được thực hiện bởi Angular mà tôi có thể sử dụng để giữ hai mảng được đồng bộ không?

+0

Tốt nhất là nếu bạn tránh được thêm $ đồng hồ như một số các câu trả lời ở đây đã được hiển thị. Đó là một cách giải quyết nhưng về chi phí hiệu suất khi mở rộng quy mô. Angular _does_ cung cấp một cách liên kết dữ liệu. Đây là liên kết nếu bạn muốn biết cách hoạt động https://toddmotto.com/one-way-data-binding-in-angular-1-5/ –

Trả lời

1

Bạn nên sử dụng $watch. Và sau đó thêm chức năng cần thiết.

Bạn có thể ghé hereofficial documentation.

$ đồng hồ (watchExpression, người nghe, [objectEquality]); Đăng ký cuộc gọi lại của người nghe để được thực thi bất cứ khi nào watchExpression thay đổi.

watchExpression được gọi trên mọi lệnh gọi $ digest() và phải trả về giá trị sẽ được xem. (watchExpression không nên thay đổi giá trị của nó khi thực hiện nhiều lần với cùng một đầu vào vì nó có thể được thực thi nhiều lần bởi $ digest() .Đó là, watchExpression phải là idempotent.) Người nghe chỉ được gọi khi giá trị từ watchExpression hiện tại và cuộc gọi trước để xemExpression không bằng nhau (ngoại trừ trường hợp ban đầu là chạy, xem bên dưới). Bất bình đẳng được xác định theo tham chiếu bất bình đẳng, so sánh chặt chẽ thông qua toán tử! == Javascript, trừ khi đối tượngEquality == true (xem điểm tiếp theo) Khi objectEquality == true, bất bình đẳng của watchExpression được xác định theo angular.equals chức năng. Để lưu giá trị của đối tượng cho sau này so sánh , chức năng angular.copy được sử dụng. Điều này do đó có nghĩa là xem các đối tượng phức tạp sẽ có bộ nhớ và hiệu suất bất lợi ý nghĩa. Điều này không nên được sử dụng để theo dõi những thay đổi trong các đối tượng có hoặc chứa các đối tượng Tệp do các giới hạn với angular.copy. Trình nghe đồng hồ có thể thay đổi kiểu máy, điều này có thể kích hoạt các trình nghe khác kích hoạt. Điều này đạt được bằng cách chạy lại trình xem cho đến khi không phát hiện thấy các thay đổi . Giới hạn lặp lại chạy lại là 10 để ngăn chặn bế tắc vòng lặp vô hạn . Nếu bạn muốn được thông báo bất cứ khi nào $ digest được gọi là , bạn có thể đăng ký chức năng watchExpression mà không có người nghe. (Hãy chuẩn bị cho nhiều cuộc gọi đến watchExpression của bạn bởi vì nó sẽ thực hiện nhiều lần trong một đơn $ tiêu hóa chu kỳ nếu có thay đổi được phát hiện.)

Sau một watcher được đăng ký với phạm vi, fn nghe là gọi không đồng bộ (thông qua $ evalAsync) để khởi tạo trình theo dõi. Trong trường hợp hiếm hoi, điều này là không mong muốn vì người nghe được gọi khi kết quả của watchExpression không thay đổi. Để phát hiện trường hợp này bên trong trình lắng nghe fn, bạn có thể so sánh newVal và oldVal.Nếu hai giá trị này giống hệt nhau (===) thì người nghe được gọi là số để khởi tạo.

3

Như Pritam đã nói. Bạn nên sử dụng đồng hồ $. Nhưng phải ràng buộc Bộ sưu tập với nó, để làm cho nó hoạt động. Và bên trong đồng hồ kết hợp các mảng.

Tìm mẫu làm việc này:

$scope.$watchCollection(angular.bind(this, function() { 
    return this.sourceArray;}), function (newVal, oldVal) { 

     var arr = []; 
     for(var i in vm.sourceArray){ 
     var shared = false; 
     for (var j in vm.targetArray) 
      if (vm.targetArray[j].id == vm.sourceArray[i].id) { 
       shared = true; 
       break; 
      } 
     if(!shared) arr.push(vm.sourceArray[i]) 
     } 
     console.log(arr); 
     vm.targetArray = vm.targetArray.concat(arr); 
    },true); 

http://plnkr.co/edit/E2inRLtwfWnb1VBymNNl?p=preview

1

Bạn có thể sử dụng $ xem biểu.

Dưới đây là một cách khác :-(underscore.js tải hoặc CDN) phương pháp

http://plnkr.co/edit/hrOrEdaQ0M7wEgWlRHlO?p=preview

  1. angular.js sao chép (angular.copy()).
  2. phương pháp mở rộng underscore.js.

    var app = angular.module('plunker', []); 
        app.controller('MainCtrl', function($scope) { 
         var vm = this; 
         vm.sourceArray = [{id: '0', name: 'someObject'}, {id: '1', name: 'anotherObject'}]; 
         vm.targetArray = angular.copy(vm.sourceArray); 
         // angular.copy(vm.sourceArray, vm.targetArray); 
         vm.push = function(){ 
          let found = false; 
          angular.forEach(vm.sourceArray, function(el){ 
          if (el.id === vm.id){ 
           el.name = vm.name; 
           found = true; 
          } 
          }); 
          if (!found){ 
          vm.sourceArray.push({id: vm.id, name: vm.name}); 
          _.extend(vm.targetArray, vm.sourceArray); 
          } 
    
        }; 
    
    
    
    vm.pushTarget = function(){ 
        let found = false; 
        angular.forEach(vm.targetArray, function(el){ 
        if (el.id === vm.id1){ 
         el.name = vm.name1; 
         found = true; 
        } 
        }); 
        if (!found){ 
        console.log({id: vm.id, name: vm.name}) 
        vm.targetArray.push({id: vm.id1, name: vm.name1}); 
        } 
    
    }; 
    

    });

bạn có thể nhận được mã underscore.js: -

_.extend = createAssigner(_.allKeys); 

// An internal function for creating assigner functions. 
var createAssigner = function(keysFunc, undefinedOnly) { 
    return function(obj) { 
     var length = arguments.length; 
     if (length < 2 || obj == null) return obj; 
     for (var index = 1; index < length; index++) { 
     var source = arguments[index], 
      keys = keysFunc(source), 
      l = keys.length; 
     for (var i = 0; i < l; i++) { 
      var key = keys[i]; 
      if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; 
     } 
     } 
     return obj; 
    }; 
    }; 

    // Retrieve all the property names of an object. 
    _.allKeys = function(obj) { 
    if (!_.isObject(obj)) return []; 
    var keys = []; 
    for (var key in obj) keys.push(key); 
    // Ahem, IE < 9. 
    if (hasEnumBug) collectNonEnumProps(obj, keys); 
    return keys; 
    }; 

    // Extend a given object with all the properties in passed-in object(s). 
1

Dưới đây là một đoạn tôi thực hiện. Lưu ý khi thay đổi mảng nguồn cả hai mảng bị ảnh hưởng, tuy nhiên khi bạn chỉ thay đổi mục tiêu, nguồn vẫn giữ nguyên.

angular.module('app', []) 
 
    .controller('mainCtrl', function($scope) { 
 
    var vm = this; 
 
    vm.sourceArray = []; 
 
    vm.source = '["change me!",{"a":3},[100]]'; 
 

 
    $scope.$watch('vm.source', function(newVal) { 
 
     try { 
 
     vm.sourceArray = JSON.parse(newVal); 
 
     vm.target = newVal; 
 
     vm.serr = null; 
 
     } catch (e) { 
 
     vm.serr = 'Invalid JSON'; 
 
     } 
 
    }); 
 
    
 
    $scope.$watch('vm.target', function(newVal) { 
 
     try { 
 
     vm.targetArray = JSON.parse(newVal); 
 
     vm.terr = null; 
 
     } catch (e) { 
 
     vm.terr = 'Invalid JSON'; 
 
     } 
 
    }); 
 

 
    //Copy whole array on change 
 
    $scope.$watch('vm.sourceArray', function(newVal) { 
 
     vm.targetArray = angular.copy(newVal); 
 
    }, true); 
 

 
    return this; 
 
    });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<div ng-app="app" ng-controller="mainCtrl as vm"> 
 
    <span>Change the inputs one at a time to see the changes take effect</span> 
 
    <h5>Source:</h5> 
 
    <input type="text" ng-model="vm.source" ng-model-options="{debounce: 300}" placeholder="Enter json formatted string for source array"><span>{{vm.serr}}</span> 
 
    <div>Model: {{vm.sourceArray|json:null:2}}</div> 
 
    <br> 
 
    <h5>Target:</h5> 
 
    <input type="text" ng-model="vm.target" ng-model-options="{debounce: 300}" placeholder="Enter json formatted string for source array"><span>{{vm.terr}}</span> 
 
    <div>Model: {{vm.targetArray|json:null:2}}</div> 
 
</div>