src/base/model.js
function initSubmodel(attr, val, ctx, persistent) {

  let submodel;

  // if value is a value -> leaf
  if (!utils.isPlainObject(val) || utils.isArray(val) || ctx.isObjectLeaf(attr)) {

    const binds = {
      //the submodel has changed (multiple times)
      "change": onChange
    };
    submodel = new ModelLeaf(attr, val, ctx, binds, persistent);
  }

  // if value is an object -> model
  else {

    const binds = {
      //the submodel has changed (multiple times)
      "change": onChange,
      //loading has started in this submodel (multiple times)
      "hook_change": onHookChange,
      // error triggered in loading
      "load_error": (...args) => ctx.trigger(...args),
      // interpolation completed
      "dataLoaded": (...args) => ctx.trigger(...args),
      //loading has ended in this submodel (multiple times)
      "ready": onReady,
    };

    // if the value is an already instantiated submodel (Model or ModelLeaf)
    // this is the case for example when a new componentmodel is made (in Component._modelMapping)
    // it takes the submodels from the toolmodel and creates a new model for the component which refers
    // to the instantiated submodels (by passing them as model values, and thus they reach here)
    if (Model.isModel(val, true)) {
      submodel = val;
      submodel.on(binds);
    }
    // if it's just a plain object, create a new model
    else {
      // construct model
      const modelType = attr.split("_")[0];

      let Modl = Model.get(modelType, true);
      if (!Modl) {
        try {
          Modl = require("../models/" + modelType).default;
        } catch (err) {
          Modl = Model;
        }
      }

      submodel = new Modl(attr, val, ctx, binds);
      // model is still frozen but will be unfrozen at end of original .set()
    }
  }

  return submodel;

  // Default event handlers for models
  function onChange(evt, path) {
    if (!ctx._ready) return; //block change propagation if model isnt ready
    path = ctx._name + "." + path;
    ctx.trigger(evt, path);
  }
  function onHookChange(evt, vals) {
    ctx.trigger(evt, vals);
  }
  function onReady(evt, vals) {
    //trigger only for submodel
    ctx.setReady(false);
    //wait to make sure it's not set false again in the next execution loop
    utils.defer(() => {
      ctx.setReady();
    });
    //ctx.trigger(evt, vals);
  }
}
function initSubmodel(attr, val, ctx, persistent) {

  let submodel;

  // if value is a value -> leaf
  if (!utils.isPlainObject(val) || utils.isArray(val) || ctx.isObjectLeaf(attr)) {

    const binds = {
      //the submodel has changed (multiple times)
      "change": onChange
    };
    submodel = new ModelLeaf(attr, val, ctx, binds, persistent);
  }

  // if value is an object -> model
  else {

    const binds = {
      //the submodel has changed (multiple times)
      "change": onChange,
      //loading has started in this submodel (multiple times)
      "hook_change": onHookChange,
      // error triggered in loading
      "load_error": (...args) => ctx.trigger(...args),
      // interpolation completed
      "dataLoaded": (...args) => ctx.trigger(...args),
      //loading has ended in this submodel (multiple times)
      "ready": onReady,
    };

    // if the value is an already instantiated submodel (Model or ModelLeaf)
    // this is the case for example when a new componentmodel is made (in Component._modelMapping)
    // it takes the submodels from the toolmodel and creates a new model for the component which refers
    // to the instantiated submodels (by passing them as model values, and thus they reach here)
    if (Model.isModel(val, true)) {
      submodel = val;
      submodel.on(binds);
    }
    // if it's just a plain object, create a new model
    else {
      // construct model
      const modelType = attr.split("_")[0];

      let Modl = Model.get(modelType, true);
      if (!Modl) {
        try {
          Modl = require("../models/" + modelType).default;
        } catch (err) {
          Modl = Model;
        }
      }

      submodel = new Modl(attr, val, ctx, binds);
      // model is still frozen but will be unfrozen at end of original .set()
    }
  }

  return submodel;

  // Default event handlers for models
  function onChange(evt, path) {
    if (!ctx._ready) return; //block change propagation if model isnt ready
    path = ctx._name + "." + path;
    ctx.trigger(evt, path);
  }
  function onHookChange(evt, vals) {
    ctx.trigger(evt, vals);
  }
  function onReady(evt, vals) {
    //trigger only for submodel
    ctx.setReady(false);
    //wait to make sure it's not set false again in the next execution loop
    utils.defer(() => {
      ctx.setReady();
    });
    //ctx.trigger(evt, vals);
  }
}
function initSubmodel ( attr , val , ctx , persistent ) { let submodel ; // if value is a value -> leaf if ( ! utils . isPlainObject ( val ) || utils . isArray ( val ) || ctx . isObjectLeaf ( attr ) ) { const binds = { //the submodel has changed (multiple times) "change" : onChange } ; submodel = new ModelLeaf ( attr , val , ctx , binds , persistent ) ; } // if value is an object -> model else { const binds = { //the submodel has changed (multiple times) "change" : onChange , //loading has started in this submodel (multiple times) "hook_change" : onHookChange , // error triggered in loading "load_error" : ( ... args ) => ctx . trigger ( ... args ) , // interpolation completed "dataLoaded" : ( ... args ) => ctx . trigger ( ... args ) , //loading has ended in this submodel (multiple times) "ready" : onReady , } ; // if the value is an already instantiated submodel (Model or ModelLeaf) // this is the case for example when a new componentmodel is made (in Component._modelMapping) // it takes the submodels from the toolmodel and creates a new model for the component which refers // to the instantiated submodels (by passing them as model values, and thus they reach here) if ( Model . isModel ( val , true ) ) { submodel = val ; submodel . on ( binds ) ; } // if it's just a plain object, create a new model else { // construct model const modelType = attr . split ( "_" ) [ 0 ] ; let Modl = Model . get ( modelType , true ) ; if ( ! Modl ) { try { Modl = require ( "../models/" + modelType ) . default ; } catch ( err ) { Modl = Model ; } } submodel = new Modl ( attr , val , ctx , binds ) ; // model is still frozen but will be unfrozen at end of original .set() } } return submodel ; // Default event handlers for models function onChange ( evt , path ) { if ( ! ctx . _ready ) return ; //block change propagation if model isnt ready path = ctx . _name + "." + path ; ctx . trigger ( evt , path ) ; } function onHookChange ( evt , vals ) { ctx . trigger ( evt , vals ) ; } function onReady ( evt , vals ) { //trigger only for submodel ctx . setReady ( false ) ; //wait to make sure it's not set false again in the next execution loop utils . defer ( ( ) => { ctx . setReady ( ) ; } ) ; //ctx.trigger(evt, vals); } }
Loads a submodel, when necessaary
@param {String} attr Name of submodel
@param {Object} val Initial values
@param {Object} ctx context / parent model
@param {Boolean} persistent true if the change is a persistent change
@returns {Object} model new submodel
Loads a submodel when necessaary