[譯] Controller間的數據共享?最佳實踐:使用Service

原文連接 : Sharing Data Between Controllers? Best Practice: Use a Service
原文做者 : DAVE CEDDIA
譯者 : 李林璞(web前端領域)
譯者注:翻譯若有疏漏,歡迎指出!感謝!轉載請保留此頭部。前端

Angular開始起來簡單易用,甚至說神奇。「哇哦!雙向綁定!」git

你會火燒眉毛地去構建你的傑做,直到碰到釘子:你正在像網上每一個人建議的那樣去構建一個獨立的組件,但怎麼和其餘組件共享數據呢?github

或許你在不一樣的路由裏有兩個視圖都須要訪問某些狀態變量,又或者你有三個分離的組件須要訪問一樣的一堆數據。web

共享數據的最佳策略是什麼呢?用一些變態的控制器繼承方案嗎?數組

固然不是,最簡單容易的方式就是使用服務(service)。this

問題

假設有兩個並排的面板,每一個面板表明一個指令(directive):spa

下面是面板1的代碼:翻譯

angular.directive('paneOne', function() {
  return {
    restrict: 'E',
    scope: {},
    template: [
      '<div>',
        '<input ng-model="p1.text">',
        '<button ng-click="p1.addToList()">Add To List</button>',
      '</div>'
    ].join(''),
    controllerAs: 'p1',
    controller: function() {
      var vm = this;
      vm.text = "";
      vm.addToList = function() {
        // TODO: add to the list in Pane 2 somehow
        vm.text = "";
      };
    }
  };
});

面板2的:雙向綁定

angular.directive('paneTwo', function() {
  return {
    restrict: 'E',
    scope: {},
    template: [
      '<ul>',
        '<li ng-repeat="item in p2.listItems">{{ item }}</li>',
      '</ul>'
    ].join(''),
    controllerAs: 'p2',
    controller: function() {
      var vm = this;
      // TODO: get this list of items from Pane 1 somehow
      vm.listItems = [];
    }
  };
});

咱們想要實現的是在面板1的輸入框中輸入某些東西,而後點擊按鈕 「Add To List」, 這條內容就會在面板2的列表中出現。rest

建立一個服務保持共享狀態

爲了在兩個甚至更多的控制器間共享數據,建立一個服務去扮演中間件的角色。這樣可使控制器(或組件)保持鬆散耦合:它們不須要知道其餘的控制器(或組件)是怎麼樣的,它們只須要知道數據源 - 你建立的中間件服務。

angular.factory('sharedList', function() {
  var list = [];

  return {
    addItem: addItem,
    getList: getList
  };

  function addItem(item) {
    list.push(item);
  }

  function getList() {
    return list;
  }
});

上面這個服務很是簡單,調用 addItem 把數據放到列表裏,而後調用 getList 獲取整個列表。這真的很簡單,甚至不須要去移除或者清空列表項,看到這個方法的簡便之處了吧。

在任何須要的地方注入服務

既然咱們已經建立好了咱們的服務,咱們就須要在任何須要訪問或修改數據的地方去注入它了。

先從面板1的控制器開始:

// Inject sharedList
controller: function(sharedList) {
  var vm = this;
  vm.text = "";
  vm.addToList = function() {
    // Stuff the item into the shared list
    sharedList.addItem(vm.text);
    vm.text = "";
  };
}

而後是面板2的控制器,獲取數據:

// Inject sharedList
controller: function(sharedList) {
  var vm = this;
  // Read the data
  vm.listItems = sharedList.getList();
}

JSBin裏看看運行狀況。

但不須要觀察器(watchers)嗎?

當我寫到這兒的時候,我很是肯定面板2中的列表在我添加一些觀察器前不會自動更新

可是接下來當我把代碼放到 JSBin 裏的時候...你瞧,它居然能夠更新!爲何呢?

  1. ng-repeat 給循環的數組設置了觀察器。

  2. 點擊 「Add To List」 觸發了一個消化週期 (digest cycle),它就會從新檢測 ng-repeat 的觀察器。

  3. 由於 sharedData.getList() 返回了一個數組的引用,觀察器就會看到 p2.listItems 已經發生了變化。這裏是關鍵:若是 getList 返回一個不一樣於由 addToList 更改的數組,這就不會觸發更新了。

因此:這種通訊方式能夠在沒有觀察器的狀況下完美運行。但若是你發現失敗了的話,檢查一下你是怎麼傳遞數據的,或許你須要明確地建立一個觀察器檢測變化。

歸納

  1. 建立一個服務去存放你的數據,並給數據建立 gettersetter 的方法。

  2. 在任何須要這個數據的地方注入這個服務。

  3. 這幾乎就是所有內容了(除非你須要觀察器 - 這種狀況下,你仍是添加一個吧)。

感謝閱讀!

相關文章
相關標籤/搜索