0
votes

I would like to be able to organize my Knockout code, like this:

  • Import a 'Master Json' file and map it.
  • Create multiple view models, which each reference particular sections of the 'Master Json' file.
  • Bind all the observables in every view model to the values of the 'Master Json' file.

Is it possible to use ko.subscribable to have everything subscribe to my json file as the master value?

Or how can I move the $.getJSON (and save) functions from inside of each view model function? Can I make a function so the getJSON results are re-usable in each of these view models?

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());

I don't want to import it many times because I think that will make a new copy each time. It should only be one Json file. When I try to move it, then I get errors that everything is undefined.

Maybe this is completely wrong approach. Does everyone put everything all into one view model? Won't it get confusing quickly?

2
It is rather unclear what you're asking tbh. Try to remove bits from your code that are not important to the actual question, yet add some code to make it a full repro of your actual scenario / attempt at doing what it is you think you need/want to do. Remember: we don't have any context, all we have is the text in your question. - Jeroen
why you want to remove $.getJSON . are you looking to remove save & Get from viewmodel and keep it somewhere outside ? - super cool
I don't entirely know if I am asking the right question. I need a jumping off point so I can get started correctly. Edited the question to hopefully add clarity. - Jennifer Michelle

2 Answers

1
votes

Yes you can use ko.subscribable for that and if you do then checkout ko.postbox, a utility wrapper for ko.subscriable. This will allow you to publish your json across view models.

So using ko.postbox, you will publish and subscribe to events/topics. Make a separate function for loading your JSON from server, and make this publish an event and all your subscribers of that event will know whenever the data is received.

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();

So whenever you need new data, you will call loader.loadJSON' and upon success, that will yield event/topic 'JsonDataLoaded. You can then subscribe to this event in your view models. Something like

function ApplesViewModel(data) {
  var self = this;

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

}

CodePen reference.

1
votes

Let me create a starting point for further conversation:

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) }
    });
}

Usage example:

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

Please correct me in case of my misunderstanding.

Update 1

Creator function:

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

Usage:

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