2015-09-15 26 views
6

在角度應用程序中,我想將元素從DOM樹的一部分移到另一部分,而無需重新加載連接到移動元素的控制器。在DOM中移動控制器時保留元素/作用域狀態

我已經創建了一個簡化的plunker來說明:http://plnkr.co/edit/sqBRM3ZQ5G9xpiNd1MXm?p=preview

在這種plunker,要保留的唯一數據是toggler狀態,但實際上,它可能是一個非常大的數據量,這可能需要一很多努力來初始化。

我想要做的是能夠將模板1從指令1移動到指令2,但我想保留觸發器的狀態。在這種情況下,如果您單擊切換器使其變爲綠色,然後單擊「從列表1移動到2」兩次,它將將其移動到指令2,但將顏色重置爲紅色。

爲了避免這種情況,我可以在不通知角度的情況下移動元素,但這顯然會導致應用程序狀態中斷。

我以爲只是將控制器從舊範圍移動到新範圍,但我覺得這會導致關閉問題,因爲舊控制器可能引用了不再在DOM中的舊元素等。

有沒有一種很好的方法來解決這個問題?

添加一些代碼,因爲StackOverflow上需要它,而是指改爲plunker:有觀點

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

而不是移動的東西,你可以不只是在一個單身工廠的數據。使用該工廠也可以作爲事件聚合器。然後,當您想要移動數據時,您可以簡單地將其從一箇中移除並將其加載到另一箇中。任何狀態都可以與事件一起發送。如果你還想加載不同的模板,你可以使用'$ templateProvider'和'$ compile'。 –

+0

加載數據後,將其緩存在$ rootScope中,然後您將可以在所有控制器中訪問它。我嘗試將$ rootScope添加到你的重擊程序中,但它似乎沒有工作。如果你對這種方法感興趣,我可以向你展示它的代碼。 – jjbskir

+0

想我在下面回答你的問題。查看plunkr的工作解決方案。如果您有任何問題或者我誤解了任何內容,請告訴我。謝謝! – jbmilgrom

回答

0

耦合應用程序的狀態/控制器是不是在我的經驗,最好的做法,但這裏是一個辦法做到這一點: revised plunkr

template1.html有一些小的變化。唯一的其他變化是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'; 
    }; 
    }; 
} 

其中現在用作templateController功能已被配置爲維持參照state對象。現在,如果您使用bodyCtrl.move12()移動模板,則可以在不中斷應用程序狀態的情況下保持累積的切換狀態。這是有效的,因爲控制器通過閉包引用外部對象。因此,它可以通過ng-include在新的DOM節點重新實例化和重新編譯,而不會重新編譯state

可能是一個更好的方式來處理

使用服務和/或$scope事件API在應用程序中不同的DOM節點之間共享狀態。

假設你有一個模板,同樣的一個在plunker介紹:

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

你想移動tc對象,裏面有所有的切換相關的狀態的,到另一個節點DOM中,您可以:

  • 分派事件下來範圍層次結構$scope.$broadcast('nameOfEvent', tc)如果目的地節點爲源的後代$scope
  • 通過注入$rootScope$rootScope.$broadcast('nameOfEvent', tc)分派事件向上範圍層次結構如果$scope.$emit('nameOfEvent', tc)如果所述目的地節點是源$scope
  • 分派事件在應用程式所有節點的祖先如果目的地節點可以是。

任何調用$範圍事件API的這些方法可以讓你傳輸數據,在這種情況下tc對象,從一個節點到另一個節點。與目的節點相關聯的所述目標控制器可以等待該事件與能夠接收所發送的數據的偵聽功能被分派:

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

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

發送的數據對象,tc,將得到綁定到具有相關聯的控制器接收到觸發的新目標節點'nameOfEvent'。現在源數據已與目標控制器對象合併,請確保目標控制器的源名稱與您的源控制器名稱相同(在此例中爲'tc'),以便源模板可以在目標控制器最終編譯並附加到目標DOM節點(該過程將在下面討論)。

刪除和添加DOM節點有點微不足道,因爲我在這裏沒有討論它,但是如果您想要輕鬆訪問源視圖/模板以在應用程序中的任何位置添加和刪除,必要時,您可以使用$templateCache

回到撥動例如,如果您切換視圖/模板本身就已經使用templateUrl與文件路徑'toggle.html'一個指令的一部分,那麼你的模板將已經投入並存儲在$templateCache下的關鍵'toggle.html'

在你的目標控制器,注入$templateCache,這將讓你找回模板:

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

進樣$編譯成你的目標控制器和$編譯目標$範圍(也注入模板目標控制器):

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

然後編譯模板添加到您的目的地控制器相關的$element(也注入到目標控制器):

$element.append($template); 

如果你想只編譯並且在接收到傳輸的數據的追加'toggle.html'模板的DOM,可以放置的bindDataToController返回函數內部的上述勢在必行編譯代碼,註冊爲事件監聽器爲'nameOfEvent'。在那裏你已經擁有它了......一個DOM節點,它已經被「移動」了,而這個節點以前在源位置建立起來的任何複雜狀態。

相關問題