2014-05-09 70 views
2

比方說,我有以下迪朗達爾代碼:迪朗達爾構造函數,但還是要記住數據

define(['durandal/app', 'plugins/http'], function (app) { 
    var vm = function(){ 
     var self = this; 
     self.myData = ko.observableArray([]); 
     } 

    }; 
    vm.activate = function() { 
     this.myData([]); 
    }; 
    vm.deactivate = function(){ 

    }; 
    return vm; 
}; 

返回一個構造函數,每一個視圖模型被激活時,我知道,這將 返回一個新的實例。

我的問題是:有無論如何,當我訪問,如果有myData()從以前的訪問,那麼我不想設置this.myData([]);,但要使用以前的myData()

我知道通過返回一個單例對象可以做到這一點,但如果我想保持構造函數,我可以做到嗎?

另一個問題,在上面的代碼中激活和停用的要點是什麼,如果你要獲得新的實例,因此保證一個'乾淨的'對象嗎?

回答

4

你可以採取幾種方法,我在下面列舉。

對於以下所有示例,請考慮項目是選擇的主題。

噴射(NO VIEW)

通過這種方法,我們注入ProjectsServices模塊(單)到項目模塊(實例)。但是,只有項目服務不提供一個或多個視圖時,此方法纔有效。下面,我會告訴你如果我們的服務模塊本身也提供一個或多個視圖,我們可以做些什麼。

ProjectsServices視圖模型(singleton)的 sevicesProjects.js

define('projectsServices', [], 
    function() { 
     var myData = null; //this may or may not be an observable 

     return { 
      myData: myData //we return an object literal, which is what makes this module a singleton 
     }; 
    } 
); 

項目視圖模型(實例) 項目。JS

define('projects', ['projectsServices'], 
    function(services) { 

     //Constructor 
     var Projects = function() { 
      this.myData = ko.observable(); //this may or may not be an observable 
     }; 

     Projects.prototype.activate = function (activationData) { 
      this.myData(services.myData); 
     }; 

     Projects.prototype.detached = function() { 
      services.myData = this.myData(); /store back to the services module for later use 
     }; 

     return Projects; //we return a constructor function, which is what makes this module an instance 
    } 
); 

主機 - 客戶機(VIEW)

通過這種方法,所述項目模塊由ProjectsServices模塊的內部,並且我們通過myData來回通過可觀察到的上activationData。此外,這種方法假定服務模塊不僅提供代碼服務,而且還提供查看服務。彈出其他表單的全局「添加聯繫人」表單是基於視圖的服務模塊的一個示例。而且,「添加聯繫人」視圖當然會有一個viewModel,它代表添加聯繫人的代碼服務。

ProjectsServices視圖模型(singleton)的 servicesProjects.js

define('projectsServices', [], 
    function() { 
     var myData = ko.observable(); //should be an observable    
    } 
); 

ProjectsServices查看 servicesProjects.html

/*We bring in the Projects module through composition and pass in the observable, `myData`, itself (not `myData()`, but `myData`)*/ 
<div> 
    <div data-bind="compose: {model: 'viewmodels/projects', activationData: myData}"> 
    </div> 
</div> 

項目視圖模型(實例) projects.js

define('projects', [], 
    function() { 

     //Constructor 
     var Projects = function() { 
      this.myDataLocal = ko.observable(); //this may or may not be an observable 
      this.myDataFromServices = null; 
     }; 

     Projects.prototype.activate = function (activationData) { 
      this.myDataFromServices = activationData 
      this.myDataLocal(activationData()); 
     }; 

     Projects.prototype.detached = function() { 
      this.myDataFromServices(this.myDataLocal()); /store back to the services module for later use 
     }; 

     return Projects; //we return a constructor function, which is what makes this module an instance 
    } 
); 

項目視圖 projects.html

/*There are infinite number of ways to bind to your myDataLocal*/ 
<div> 
    <div data-bind="text: myDataLocal}"> 
    </div> 
</div> 

發佈 - 訂閱

通過這種方法,我們利用Durandal的內置酒吧/分設施通過app。這種方法可以用於上面給出的注入或主機客戶端。策略是發佈來自實例模塊的activate處理程序的請求消息,並且在同一處理程序中接收回復消息,這兩個消息的目的是請求並提供myData(假設其早先被保存)。當我們準備將myData保存回服務模塊時,我們會發送另一個消息myData作爲有效負載。

ProjectsServices視圖模型(單) servicesProjects.js

define('projectsServices', ['durandal/app'], 
    function(app) { 
     var 
      myData = null, //this may or may not be an observable 

      activate = function() { 
       app.on('requestForMyData').then(function() { 
        app.trigger('responseMyData', myData); 
       }); 
       app.on('storeMyData').then(function (data) { 
        myData = data; //where 'data' is the payload 
       }); 
      }, 

      detached = function() { 
       app.off('requestForMyData'); 
       app.off('storeMyData'); 
      }; 

     return { 
      myData: myData, //we return an object literal, which is what makes this module a singleton 
      activate: activate, 
      detached: detached 
     }; 
    } 
); 

項目視圖模型(實例) projects.js

define('projects', ['durandal/app'], 
    function(app) { 

     //Constructor 
     var Projects = function() { 
      this.myData = ko.observable(); //this may or may not be an observable 
     }; 

     Projects.prototype.activate = function() { 
      var that = this; 
      app.on('responseMyData').then(function (data) { 
       that.myData(data); 
      }); 
      app.trigger('requestForMyData'); //no payload 
     }; 

     Projects.prototype.detached = function() { 
      app.trigger('storeMyData', this.myData()); 
      app.off('responseMyData'); 
     }; 

     return Projects; //we return a constructor function, which is what makes this module an instance 
    } 
); 

的觀點並不改變在這種情況下,如此他們不在這裏提供。

消息總線

這種方法幾乎是相同的發佈 - 訂閱方法,不同之處在於我們使用一個客戶端的消息總線,如postal.js。你會看到更精緻的。它也恰好是我們在生產中採用的方法。這種方法應該與上面的主機 - 客戶端方法一起使用,只是我們只是傳遞一個消息通道,而不是數據本身。

  • 您可以下載postal.js here
  • 請與我(@estaylorco)在Github上與Jim Cowart(@ifandelse)交流here,herehere
  • 查看postal.request-response的RC(我做了而不是,因爲它在預覽中使用),以及我在那裏的交流。 postal.request-response是我所要求的(雙向頻道),它僅適用於您正在使用的場景。它極大地簡化了請求響應場景。

ProjectsServices視圖模型(singleton)的 servicesProjects.js

define('projectsServices', ['postal'], 
    function(postal) { 
     var 
      outletMessageChannel = 'someuniqueidentifier', 
      subscriptions = [], 
      myData = null, //this may or may not be an observable 

      activate = function() { 
       var that = this; 
       subscriptions.push(postal.subscribe({ 
        channel: outletMessageChannel, 
        topic: 'request.mydata', 
        callback: function() { 
        postal.publish({ 
         channel: outletMessageChannel, 
         topic: 'response.mydata', 
         data: that.myData 
        }); 
        } 
       })); 
       subscriptions.push(postal.subscribe({ 
        channel: outletMessageChannel, 
        topic: 'store.mydata', 
        callback: function (data) { 
         that.myData = data; 
        } 
       })); 
      }, 

      detached = function() { 
       //I'm using underscore.js here, but you can use any approach to iterate over subscriptions 
       _.each(subscriptions, function(sub) { 
        sub.unsubscribe(); 
        sub.callback = null; 
        sub = null; 
       }); 
       subscriptions = null; 
      }; 

     return { 
      myData: myData, //we return an object literal, which is what makes this module a singleton 
      activate: activate, 
      detached: detached 
     }; 
    } 
); 

ProjectsServices查看 servicesProjects.html

/*We bring in the Projects module through composition and pass in the message channel*/ 
<div> 
    <div data-bind="compose: {model: 'viewmodels/projects', activationData: outletMessageChannel}"> 
    </div> 
</div> 

項目視圖模型(實例) projects.js

define('projects', ['postal'], 
    function(postal) { 

     //Constructor 
     var Projects = function() { 
      this.subscriptions = []; 
      this.outletMessageChannel = ''; 
      this.myData = ko.observable(); //this may or may not be an observable 
     }; 

     Projects.prototype.activate = function (activationData) { 
      this.outletMessageChannel = activationData; 

      var that = this; 

      subscriptions.push(postal.subscribe({ 
       channel: this.outletMessageChannel, 
       topic: 'response.mydata', 
       callback: function (data) { 
        that.myData(data); 
       } 
      })); 

      postal.publish({ 
       channel: this.outletMessageChannel, 
       topic: 'request.mydata', 
       data: null //no payload 
      });    

     }; 

     Projects.prototype.detached = function() { 
      postal.publish({ 
       channel: this.outletMessageChannel, 
       topic: 'store.mydata', 
       data: this.myData() 
      }); 

      //I'm using underscore.js here, but you can use any approach to iterate over subscriptions 
      _.each(this.subscriptions, function(sub) { 
       sub.unsubscribe(); 
       sub.callback = null; 
       sub = null; 
      }); 
      this.subscriptions = null; 
     }; 

     return Projects; //we return a constructor function, which is what makes this module an instance 
    } 
); 

注意,項目視圖不會在這種情況下發生變化,所以這裏不包括它。

+0

感謝您的詳細解答。我會試試看。 – neo

0

是的,你可以做到這一點。

例如,在我們的應用程序,每個模塊有兩個部分:XxxServices的命名約定下面一個單模塊和實例模塊,叫xxx,其中xxx是你的模塊的規範名稱:

  • ProjectsServices(singleton)的
  • 項目(實例)

有[至少]兩種方法可以使服務提供給實例:通過迪朗達爾組合物,通過在一個activationData對象,並通過依賴新生使用RequireJS進行密碼注入。 (另一種方法是在請求響應場景下使用客戶端消息總線,例如postal.js,但這是一匹不同顏色的馬)。

如果你不熟悉這些技術,我可以詳細說明你是否願意。

+0

嗨,Eric,請詳細說明。一個例子會很棒!謝謝。 – neo

+0

@neo O.K.看到我的新答案,這很長。但它描述了所有的情景。請享用! –