Looks like we can't reproduce the issue or there's a problem in the test case provided.
  1. #1
    Sencha User
    Join Date
    Oct 2011
    Posts
    21
    Vote Rating
    0
    OliverColeman is on a distinguished road

      0  

    Default Model class required by Store not loaded

    Model class required by Store not loaded


    Using Ext 4.0.7, Firefox 8 and Chrome 16, Ubuntu 11.10.

    I have a Store, Model and Controller. The Store config has the 'model' property set to the name of the Model, and the 'stores' property in the Controller is an array containing the name of the Store. The Store class file is loaded dynamically, but the Model class file isn't. Perhaps this is the expected behaviour, but I'm guessing not, and it seems particularly unintuitive and annoying if so! If the Controller has the Model specified in its config in the 'models' property then the Model class file is loaded.

    Code:
    Ext.Loader.setConfig({enabled:true});Ext.Loader.setPath('Ext', '/installations/co/public_html/sites/all/libraries/ext/src');
    Ext.Loader.setPath('CO', '/installations/co/public_html/sites/default/files/ext/CO');
    Ext.application({
      controllers: [ 'Files' ],
      autoCreateViewport: 1,
      name: 'CO',
      appFolder: '/installations/co/public_html/sites/default/files/ext/CO'
    });
    Code:
    Ext.define('CO.controller.Files', {  extend: 'Ext.app.Controller',
      
      //models: ['CoFile'],
      stores: ['CoFileTree'],
      
      init: function() {
        //...
        this.callParent(arguments);
      }
    });
    Code:
    Ext.define('CO.store.CoFileTree', {
      model: "CoFile",
      nodeParam: "nid",
      root: {
        expanded: "true"
      },
      listeners: {
        beforeload: function(store, operation) {
            if (operation.node.parentNode) {
              // Include parent node data so we know the context of the node we're loading/expanding.
              this.proxy.extraParams['parent'] = Ext.JSON.encode(operation.node.parentNode.data);
            }
            else {
              this.proxy.extraParams['parent'] = null;
            }
          }
      },
      requires: [
        "Ext.data.proxy.Rest"
      ],
      proxy: {
        type: "rest",
        url: "/installations/co/public_html/ext/rest/store/CoFileTree",
        reader: {
          type: "json",
          root: "parentIdCoFileList"
        }
      },
      storeId: "CoFileTree",
      alternateClassName: [
        "store.CoFileTree"
      ],
      extend: "Ext.data.TreeStore"
    });
    Code:
    Ext.define('CO.model.CoFile', {
      alternateClassName: [
        "model.CoFile"
      ],
      associations: [
        {
          associationKey: "parentIdCoFile",
          foreignKey: "parentId",
          getterName: "getParentIdCoFile",
          model: "CO.model.CoFile",
          primaryKey: "nid",
          setterName: "setParentIdCoFile",
          type: "belongsTo"
        },
        {
          associationKey: "parentIdCoFileList",
          foreignKey: "parentId",
          model: "CO.model.CoFile",
          name: "parentIdCoFileList",
          primaryKey: "nid",
          type: "hasMany"
        },
        {
          associationKey: "docSetRootFileNidNodeCoDocumentSetList",
          foreignKey: "field_doc_set_root_file_nid",
          model: "CO.model.NodeCoDocumentSet",
          name: "docSetRootFileNidNodeCoDocumentSetList",
          primaryKey: "nid",
          type: "hasMany"
        },
        {
          associationKey: "schoolPublicFolderNidNodeCoSchoolList",
          foreignKey: "field_school_public_folder_nid",
          model: "CO.model.NodeCoSchool",
          name: "schoolPublicFolderNidNodeCoSchoolList",
          primaryKey: "nid",
          type: "hasMany"
        },
        {
          associationKey: "uidUser",
          foreignKey: "uid",
          getterName: "getUidUser",
          model: "CO.model.User",
          primaryKey: "uid",
          setterName: "setUidUser",
          type: "belongsTo"
        },
        {
          associationKey: "nidCommentList",
          foreignKey: "nid",
          model: "CO.model.Comment",
          name: "nidCommentList",
          primaryKey: "cid",
          type: "hasMany"
        }
      ],
      fieldSyncMap: {
        field_co_file_class_value: "iconCls",
        iconCls: "field_co_file_class_value",
        text: "title",
        title: "text"
      },
      fields: [
        {
          name: "allowDrag"
        },
        {
          name: "allowDrop"
        },
        {
          name: "body",
          type: null
        },
        {
          defaultValue: 0,
          name: "changed",
          type: "int"
        },
        {
          name: "cls"
        },
        {
          defaultValue: 0,
          name: "comment",
          type: "int"
        },
        {
          defaultValue: 0,
          name: "created",
          type: "int"
        },
        {
          name: "draggable"
        },
        {
          name: "editable"
        },
        {
          name: "expandable"
        },
        {
          name: "expanded"
        },
        {
          name: "field_co_file_class_value",
          type: "string"
        },
        {
          name: "field_co_file_code_value",
          type: "int"
        },
        {
          name: "field_co_file_doc_set_nid",
          type: "int"
        },
        {
          name: "field_co_file_file_data",
          type: "string"
        },
        {
          name: "field_co_file_file_fid",
          type: "int"
        },
        {
          name: "field_co_file_file_list",
          type: "int"
        },
        {
          name: "field_co_file_parents_index_value",
          type: "int"
        },
        {
          name: "field_co_file_parents_nid",
          type: "int"
        },
        {
          name: "field_co_file_school_public_nid",
          type: "int"
        },
        {
          name: "field_co_file_template_value",
          type: "int"
        },
        {
          name: "field_co_file_top_folder_nid",
          type: "int"
        },
        {
          name: "field_co_file_type_value",
          type: "int"
        },
        {
          name: "iconCls"
        },
        {
          name: "index",
          type: "int"
        },
        {
          defaultValue: "",
          name: "language",
          type: "string"
        },
        {
          name: "leaf"
        },
        {
          defaultValue: 0,
          name: "moderate",
          type: "int"
        },
        {
          name: "nid",
          type: "int"
        },
        {
          name: "parentId",
          type: "int"
        },
        {
          name: "parentId_original",
          type: "int"
        },
        {
          name: "primary_share_point_in_docset"
        },
        {
          defaultValue: 0,
          name: "promote",
          type: "int"
        },
        {
          name: "qtip"
        },
        {
          name: "qtitle"
        },
        {
          name: "shared_in_other_docset"
        },
        {
          name: "shared_in_this_docset"
        },
        {
          defaultValue: 1,
          name: "status",
          type: "int"
        },
        {
          defaultValue: 0,
          name: "sticky",
          type: "int"
        },
        {
          name: "teaser",
          type: null
        },
        {
          name: "text"
        },
        {
          defaultValue: "",
          name: "title",
          type: "string"
        },
        {
          defaultValue: 0,
          name: "tnid",
          type: "int"
        },
        {
          defaultValue: 0,
          name: "translate",
          type: "int"
        },
        {
          defaultValue: "",
          name: "type",
          type: "string"
        },
        {
          defaultValue: 0,
          name: "uid",
          type: "int"
        },
        {
          defaultValue: 0,
          name: "vid",
          type: "int"
        }
      ],
      idProperty: "nid",
      proxy: {
        reader: {
          root: "cofile",
          type: "json"
        },
        type: "rest",
        url: "/installations/co/public_html/ext/rest/model/CoFile",
        writer: new Ext.data.writer.Json()
      },
      requires: [
        "Ext.data.writer.Json",
        "Ext.data.proxy.Rest"
      ],
      validations: [
        {
          field: "title",
          type: "presence"
        },
        {
          field: "field_co_file_type_value",
          type: "presence"
        },
        {
          field: "field_co_file_class_value",
          type: "presence"
        },
        {
          field: "field_co_file_template_value",
          list: [
            0,
            1
          ],
          type: "inclusion"
        }
      ],
      extend: "CO.model.DrupalModel"
    });

    Code:
    /**
     * @class CO.model.DrupalModel
     * @extends Ext.data.Model
     * 
     * <p>
     * The DrupalModel class provides a Model with some custom functions to
     * facilitate integration of Drupal with Ext.
     * </p>
     * 
     * <p>
     * <em>Field synchronisation:</em> This function allows keeping specific field
     * values in sync with each other. The fieldSyncMap property contains a list of
     * field to field mappings containing the names of fields whose values should be
     * kept in sync. This property is generally defined in sub-classes (since in
     * most cases we want the same behaviour across all instances of the same
     * Model), but can also be set in the config options for individual instances.
     * Member names should be field names to monitor for changes, values should be
     * field names to update when the corresponding field referred to by the member
     * name changes. When a field value is set via the set() function and the field
     * name is a member of the fieldSyncMap Object, then the field whose name is the
     * value of this member will be updated with the same value (via the set()
     * function defined on Ext.data.Model). "Setting" cycles do not occur when the
     * fieldSyncMap contains field to field mappings that are opposites. If the
     * set(fieldName, value) function is called with the fieldName argument being a
     * map of field names to values, and fieldSyncMap contains a pair of opposite
     * definitions, and both values are specified in the fieldName argument, then if
     * one of the specified values == null then it will be ignored (this is most
     * useful when all the data for a Model is loaded).
     * </p>
     */
    
    
    Ext.define('CO.model.DrupalModel', {
      extend: 'Ext.data.Model',
      alternateClassName: 'model.DrupalModel',
      
      /**
       * @property {Object} fieldSyncMap
       * Contains a list of field to field mappings containing the names of fields 
       * whose values should be kept in sync.
       */
      fieldSyncMap: {},
      
      /**
       * Contains one of the pairs of each pair of opposite definitions in 
       * fieldSyncMap.
       */
      fieldSyncMapOpposites: {},
      /**
       * Contains the definitions that don't have an opposite definition in 
       * fieldSyncMap.
       */
      fieldSyncMapNonOpposites: {},
      
      /**
       * Creates the DrupalModel.
       * @param {Object} config (optional) Config object.
       */
      constructor: function(config) {
        if ('fieldSyncMap' in config) {
          this.fieldSyncMap = config.fieldSyncMap;
        }
        
        // Sort field mapping definitions into pairs of opposites and unique.
        // This is used to help resolve conflicts when multiple field values are 
        // set together.
        for (var field1 in this.fieldSyncMap) {
          var field2 = this.fieldSyncMap[field1];
          // If there is an opposite definition.
          if (field2 in this.fieldSyncMap && this.fieldSyncMap[field2] == field1) {
            // If we haven't yet recorded this pair.
            if (!(field2 in this.fieldSyncMapOpposites)) {
              this.fieldSyncMapOpposites[field1] = field2;
            }
          }
          else { // It as a unique definition.
            this.fieldSyncMapNonOpposites[field1] = field2;
          }
        }
        
        this.callParent(arguments);
      },
      
      
      /**
       * Sets the given field to the given value, marks the instance as dirty.
       * If the specified field names are members of fieldSyncMap then the 
       * corresponding fields will also have their values updated.
       * @param {String/Object} fieldName The field to set, or an object containing key/value pairs
       * @param {Object} value The value to set
       */
      set: function(fieldName, value) {
        // If we're passed an Object mapping field names to values, check for and 
        // try to resolve conflicts between mapping definitions in 
        // fieldSyncMap and setting both fields at once in this request. 
        if ((arguments.length == 1 && Ext.isObject(fieldName))) {
          // Try to resolve conflicts involving pairs of opposite field sync 
          // definitions first.
          for (var field1 in this.fieldSyncMapOpposites) {
            var field2 = this.fieldSyncMapOpposites[field1];
            // If both fields are set in fieldName and have different values.
            if (field1 in fieldName && field2 in fieldName && fieldName[field1] !== fieldName[field2]) {
              // If one of them is null (false, 0, empty), remove it.
              if (fieldName[field1] == null || fieldName[field1] == "" || fieldName[field1] == "0") {
                delete fieldName[field1];
              }
              else if (fieldName[field2] == null || fieldName[field2] == "" || fieldName[field2] == "0") {
                delete fieldName[field2];
              }
              // Else there's nothing sensible we can do.
            }
          }
          
          // Try to resolve any remaining conflicts.
          for (var field1 in this.fieldSyncMapNonOpposites) {
            var field2 = this.fieldSyncMapNonOpposites[field1];
            // If both fields are set in fieldName.
            if (field1 in fieldName && field2 in fieldName) {
              // Prioritise the master field.
              delete fieldName[field2];
            }
          }
        }
        
        this.callParent(arguments);
        
        // If we're passed a field name and value.
        if (arguments.length == 2 && !Ext.isObject(fieldName)) {
          // If this field is in the field sync map update the corresponding field.
          if (fieldName in this.fieldSyncMap) {
            this.callParent([this.fieldSyncMap[fieldName], value]);
          }    
        }
      }
    });

  2. #2
    Sencha - Senior Forum Manager mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    36,522
    Vote Rating
    814
    mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute

      0  

    Default


    You need to add your model to the requires array.
    Mitchell Simoens @SenchaMitch
    Sencha Inc, Senior Forum Manager
    ________________
    Check out my GitHub, lots of nice things for Ext JS 4 and Sencha Touch 2
    https://github.com/mitchellsimoens

    Think my support is good? Get more personalized support via a support subscription. https://www.sencha.com/store/

    Need more help with your app? Hire Sencha Services services@sencha.com

    Want to learn Sencha Touch 2? Check out Sencha Touch in Action that is in print!

    When posting code, please use BBCode's CODE tags.

Thread Participants: 1

Tags for this Thread