【问题标题】:Knockout: multiple view models subscribe to Json淘汰赛:多个视图模型订阅 Json
【发布时间】:2016-01-27 17:58:09
【问题描述】:

我希望能够像这样组织我的 Knockout 代码:

  • 导入“Master Json”文件并进行映射。
  • 创建多个视图模型,每个模型都引用“Master Json”文件的特定部分。
  • 将每个视图模型中的所有可观察对象绑定到“Master Json”文件的值。

是否可以使用 ko.subscribable 让所有内容都订阅我的 json 文件作为主值?

或者如何从每个视图模型函数内部移动 $.getJSON(和保存)函数?我可以创建一个函数,以便 getJSON 结果可在每个视图模型中重复使用吗?

function ApplesViewModel ( data ) {

    // ko.observables here 

    //Get Json
    $.getJSON("json/masterJson.json", function(allData) {
        var mappedSlides = $.map(allData, function(item) { return new Slide(item) });
        self.slides(mappedSlides);
    });    

    //Save Json
    self.save = function() {
        $.ajax("/masterJson", {
            data: ko.toJSON({ slides: self.slides }),
            type: "post", contentType: "application/json",
            success: function(result) { alert(result) }
        });
    }; 
}

function BananasViewModel( data ) {
    //same as ApplesViewModel but with different observables
}

function CarrotsViewModel( data ) {
    //same as ApplesViewModel but with different observables
}

ko.applyBindings(new ApplesViewModel());
ko.applyBindings(new BananasViewModel());
ko.applyBindings(new CarrotsViewModel());

我不想多次导入它,因为我认为每次都会制作一个新副本。它应该只有一个 Json 文件。当我尝试移动它时,我会收到所有内容都未定义的错误。

也许这是完全错误的做法。每个人都将所有内容都放在一个视图模型中吗?会不会很快变得混乱?

【问题讨论】:

  • 目前还不清楚你在问什么。尝试从您的代码中删除对实际问题重要的位,但添加一些代码以使其完全重现您的实际场景/尝试做它你认为你需要/想要做什么。请记住:我们没有任何上下文,所有我们只有您问题中的文字。
  • 为什么要删除 $.getJSON 。您是否要从视图模型中删除 saveGet 并将其保留在外面的某个地方?
  • 我不完全知道我问的问题是否正确。我需要一个起点,这样我才能正确开始。编辑了问题以希望增加清晰度。

标签: knockout.js knockout-mapping-plugin


【解决方案1】:

是的,您可以为此使用ko.subscribable,如果这样做,请查看ko.postbox,这是ko.subscriable 的实用程序包装器。这将允许您跨视图模型发布您的 json。

因此,使用ko.postbox,您将发布订阅事件/主题。制作一个单独的函数来从服务器加载您的 JSON,并使其发布一个事件,并且该事件的所有订阅者将在收到数据时知道。

function DataLoader(){
  var self = this;
  self.loadJSON = function(){
    //Load JSON using getJSON from server and publish event "JsonDataLoaded"
    setTimeout(function(){
          ko.postbox.publish("JsonDataLoaded", data);
    }, 3000)
  };
}

var loader = new DataLoader();
loader.loadJSON();

因此,每当您需要新数据时,您都会致电loader.loadJSON' and upon success, that will yield event/topic 'JsonDataLoaded。然后,您可以在视图模型中订阅此事件。像

function ApplesViewModel(data) {
  var self = this;

  ko.postbox.subscribe("JsonDataLoaded", function(newData){
    ko.mapping.fromJS(newData,{},self);
  },self,true);

}

CodePen 参考。

【讨论】:

  • 这需要我一天左右的时间来理解这一点......几个问题:为什么 setTimeout - 用于演示还是有必要?如果我有一个
  • 是的,setTimeout 用于演示,模拟 getJson 响应。不确定also update one Json file 是什么意思?您是指保存回相同的json文件吗?如果是,要保存什么以及何时保存?
  • 例如,如果用户在applesViewModel中编辑了一个值,然后用户在bananasViewModel中编辑了一个值,这两个更新会反映在同一个Json副本中吗?我不需要实际保存到服务器。我只需要更新 master-Json 客户端。
  • 使用上述方法,编辑将在每个视图模型本地进行,不会反映在 master-json 文件中。
  • 谢谢,我从您的回答中了解到,最好将所有内容都放在一个视图模型中,这样可以节省我很多天的反复试验。
【解决方案2】:

让我为进一步的对话创建一个起点:

function ApplesViewModel(data) {
    self.slides = ko.observableArray($.map(data, function(item) { return new Slide(item) }));
    // setup other properties here 
}

function getFruitViewModel(modelUrl, targetModelHolder) {
    $.getJSON(modelUrl, function(allData) {
        targetModelHolder(new ApplesViewModel(allData));
    });    
}

function saveFruitViewModel(saveModelUrl, targetModelHolder) {
    $.ajax(saveModelUrl, {
        data: ko.toJSON(ko.unwrap(targetModelHolder)),
        type: "post", contentType: "application/json",
        success: function(result) { alert(result) }
    });
}

使用示例:

    var applesViewModel = ko.observable();
    getFruitViewModel("json/masterJson.json", applesViewModel);
    // some work with view model(s)
    saveFruitViewModel("/masterJson", applesViewModel);

如有误解请指正。

更新 1

创作者功能:

function getFruitViewModel(modelUrl, targetModelHolder, creator) {
    $.getJSON(modelUrl, function(allData) {
        targetModelHolder(creator(allData));
    });    
}

用法:

    getFruitViewModel("json/masterJson.json", applesViewModel, function(data) { return new ApplesViewModel(data); });

【讨论】:

  • 您好,TSV,我认为答案是我应该在每个要存储我的信息的 Json 文件中使用一个视图模型。听起来对吗?题外话:我根据我们的其他对话发布了一个新问题,关于 Knockout 模板,如果您有兴趣:stackoverflow.com/questions/33390862/…
  • @JenniferMichelle 是的,我认为如果水果模型相同,您可以使用一个类来描述每种水果。如果模型不同,您也可以使用“getFruitViewModel”,但您应该传递一个创建者函数(更新 1)。
猜你喜欢
  • 2018-07-21
  • 2013-01-26
  • 1970-01-01
  • 2015-01-29
  • 2012-09-20
  • 2016-02-29
  • 2013-06-07
  • 1970-01-01
  • 2012-11-29
相关资源
最近更新 更多