2015-09-15 17 views
6

Trong ứng dụng góc, tôi muốn di chuyển một phần tử từ một phần của cây DOM sang một phần khác mà không phải tải lại bộ điều khiển được gắn vào phần tử đã di chuyển.Giữ trạng thái phần tử/phạm vi khi di chuyển bộ điều khiển trong DOM

tôi đã tạo ra một plunker đơn giản để minh họa: http://plnkr.co/edit/sqBRM3ZQ5G9xpiNd1MXm?p=preview

Trong plunker này, dữ liệu chỉ được giữ lại là trạng thái toggler, nhưng trong thực tế nó có thể là một số lượng rất lớn dữ liệu, mà có thể yêu cầu một rất nhiều nỗ lực để khởi tạo.

Điều tôi muốn làm là có thể di chuyển mẫu 1 từ chỉ thị 1 sang chỉ thị 2, nhưng tôi muốn giữ trạng thái của người chuyển đổi. Trong trường hợp này, nếu bạn nhấp vào trình chuyển đổi để làm cho màu xanh lục và nhấp vào "di chuyển từ danh sách 1 đến 2" hai lần, nó sẽ chuyển nó sang chỉ thị 2 nhưng đặt lại màu thành màu đỏ.

Để phá vỡ điều này, tôi chỉ có thể di chuyển phần tử mà không thông báo góc cạnh, nhưng điều này rõ ràng là tạo ra trạng thái ứng dụng bị hỏng.

Tôi nghĩ đến việc di chuyển bộ điều khiển từ phạm vi cũ sang phạm vi mới, nhưng tôi cảm thấy điều này sẽ gây ra sự cố đóng cửa vì bộ điều khiển cũ có thể tham chiếu đến phần tử cũ không còn trong DOM, v.v.

Có cách nào tốt đẹp để giải quyết vấn đề này không?

Thêm một số mã vì StackOverflow đòi hỏi nó, nhưng tham khảo plunker thay vì: trạng thái ứng dụng

angular.module('app').controller('bodyController', ['$element', function ($element) { 

    this.contents1 = [{ 
     path: 'template1.html' 
    }, { 
     path: 'template2.html' 
    }]; 

    this.contents2 = [{ 
     path: 'template3.html' 
    }, { 
     path: 'template4.html' 
    }]; 

    this.move12 = function() { 
     this.contents2.push(this.contents1.pop()); 
    }; 

    this.move21 = function() { 
     this.contents1.push(this.contents2.pop()); 
    }; 

    this.naiveMove12 = function() { 
     var $elem = $($element); 
     $elem.find('container-list:eq(0) > div').last() 
      .appendTo($elem.find('container-list').eq(1)); 
    }; 

    this.naiveMove21 = function() { 
     var $elem = $($element); 
     $elem.find('container-list:eq(1) > div').last() 
      .appendTo($elem.find('container-list').eq(0)); 
    }; 

    this.logScope = function() { 
     var $elem = $($element); 
     [].forEach.call($elem.find('container-list'), function (elem, idx) { 
      console.log(idx + ': ', angular.element(elem).isolateScope().containerListCtrl); 
     }); 
    }; 
}]); 
+5

Thay vì di chuyển nội dung, bạn có thể không chỉ có dữ liệu trong một nhà máy đơn lẻ hay không. Sử dụng nhà máy đó cũng như một bộ tổng hợp sự kiện. Sau đó, khi bạn muốn di chuyển dữ liệu, bạn đơn giản xóa dữ liệu khỏi một và tải dữ liệu đó vào một tệp khác. Bất kỳ trạng thái nào cũng có thể được gửi cùng với sự kiện. Nếu bạn cũng muốn tải lên các mẫu khác nhau, bạn có thể sử dụng '$ templateProvider' và' $ compile'. –

+0

Sau khi tải bộ nhớ cache dữ liệu trong $ rootScope, sau đó bạn sẽ có quyền truy cập vào nó trong tất cả các bộ điều khiển của bạn. Tôi đã thử thêm $ rootScope để plunker của bạn, nhưng nó dường như không được làm việc. Nếu bạn quan tâm đến cách tiếp cận này tôi có thể cho bạn thấy mã cho nó. – jjbskir

+0

Hãy suy nghĩ tôi đã trả lời câu hỏi của bạn bên dưới. Kiểm tra các plunkr cho giải pháp làm việc. Xin vui lòng cho tôi biết nếu bạn có bất kỳ câu hỏi hoặc nếu tôi hiểu lầm bất cứ điều gì cả. Cảm ơn! – jbmilgrom

Trả lời

0

nối với quan điểm/điều khiển không phải là thực hành tốt nhất trong kinh nghiệm của tôi, nhưng đây là một cách để làm điều đó: revised plunkr.

Có một vài thay đổi nhỏ trong template1.html. Chỉ thay đổi khác nằm trong templateController.js:

angular.module('app').controller('templateController', statefulTemplateCtrl()); 

function statefulTemplateCtrl() { 
    var state = {color: 'red'}; 
    return function(){ 
    this.state = state; 

    // this.color = 'red'; 

    this.toggleColor = function() { 
     state.color = (state.color === 'red') ? 'green' : 'red'; 
    }; 
    }; 
} 

nơi các chức năng hiện nay được sử dụng như templateController đã được cấu hình để duy trì tham chiếu đến một đối tượng state. Bây giờ nếu bạn di chuyển mẫu bằng cách sử dụng bodyCtrl.move12(), bạn sẽ có thể giữ trạng thái chuyển đổi được tích lũy mà không vi phạm trạng thái đơn đăng ký của mình. Điều này làm việc vì bộ điều khiển có tham chiếu đến một đối tượng bên ngoài thông qua một đóng. Kết quả là, nó có thể được tái khởi tạo và biên dịch lại tại nút DOM mới bằng cách ng-include mà không tái instatiating state.

Có lẽ một cách tốt hơn để xử lý

Sử dụng dịch vụ và/hoặc $scope sự kiện API để chia sẻ trạng thái giữa các nút DOM khác nhau trong ứng dụng của bạn.

Giả sử bạn có mẫu, cùng một giới thiệu vào năm plunker của bạn:

<div ng-class="{ red: (tc.color === 'red'), green: (tc.color === 'green') }" ng-click="tc.toggleColor()">Toggler</div> 

Và bạn muốn di chuyển các đối tượng tc, mà nhà tất cả các trạng thái bật tắt liên quan đến bạn, đến nút khác trong DOM, bạn có thể:

  • gửi một sự kiện xuống phạm vi hệ thống cấp bậc với $scope.$broadcast('nameOfEvent', tc) nếu node đích là một hậu duệ của nguồn $scope
  • gửi một sự kiện lên phạm vi hệ thống cấp bậc nếu $scope.$emit('nameOfEvent', tc) nếu node đích là tổ tiên của nguồn $scope
  • gửi một sự kiện cho tất cả các nút trong ứng dụng của bạn bằng cách tiêm $rootScope$rootScope.$broadcast('nameOfEvent', tc) nếu node đích có thể là .

Gọi bất kỳ phương thức nào trong API sự kiện $ scope này sẽ cho phép bạn truyền dữ liệu, trong trường hợp này là đối tượng tc, từ nút này sang nút khác. Bộ điều khiển điểm đến gắn liền với nút đích có thể được chờ đợi sự kiện này được gửi đi với một chức năng nghe có thể nhận được dữ liệu truyền:

function bindDataToController(destinationCtrl){ 
    return function(event, tc){ 
    angular.extend(destinationCtrl, tc); 
    }; 
} 

$scope.$on('nameOfEvent', bindDataToController(this)); 

Đối tượng dữ liệu truyền đi, tc, sẽ bị ràng buộc với điều khiển đi kèm với nút đích mới khi nhận được kích hoạt 'nameOfEvent'. Bây giờ dữ liệu nguồn đã được hợp nhất với đối tượng điều khiển đích, hãy đảm bảo rằng bộ điều khiển đích của bạn được đặt cùng tên controllerAs làm bộ điều khiển nguồn, trong trường hợp này là 'tc', sao cho mẫu nguồn có thể tham khảo chính xác bộ điều khiển đích khi nó cuối cùng được biên dịch và đính kèm vào nút DOM đích (quá trình được thảo luận dưới đây).

Xóa và thêm nút DOM hơi tầm thường như bạn đã đề cập, vì vậy tôi chưa thảo luận ở đây, nhưng nếu bạn muốn truy cập dễ dàng vào chế độ xem/mẫu nguồn để thêm và xóa ở bất kỳ vị trí nào trong ứng dụng của bạn cần thiết, bạn có thể sử dụng $templateCache.

Trở lại với ví dụ chuyển đổi, nếu xem Toggle bạn/mẫu là chính nó đã là một phần của một chỉ thị mà sử dụng templateUrl với đường dẫn tập tin 'toggle.html', sau đó mẫu của bạn sẽ đã được đưa vào và lưu trữ trong $templateCache dưới phím 'toggle.html' .

Trong điều khiển điểm đến của bạn, tiêm $templateCache, mà sẽ cho phép bạn để lấy mẫu:

var template = $templateCache.get('toggle.html'); 

Tiêm $ biên dịch vào bộ điều khiển điểm đến của bạn và $ biên dịch mẫu với điểm đến $ phạm vi (cũng tiêm vào điều khiển đích):

var $template = $compile(template)($scope); 

sau đó nối các mẫu biên soạn với $element (cũng tiêm vào bộ điều khiển đích) kết hợp với bộ điều khiển điểm đến của bạn:

$element.append($template); 

Nếu bạn muốn chỉ biên dịch và thêm các 'toggle.html' mẫu để DOM khi nhận được dữ liệu truyền đi, bạn có thể đặt mã biên dịch bắt buộc trên bên trong hàm trả lại bindDataToController, đăng ký là người biết lắng nghe sự kiện cho 'nameOfEvent'. Và ở đó bạn có nó! ... Nút DOM đã được "di chuyển" với bất kỳ trạng thái phức tạp nào đã được xây dựng trước đó tại vị trí nguồn.

Các vấn đề liên quan