Search code examples
ember.jsember-dataember-cli

Couldn't access related models in ember.js 2.0 using ember-data


I'm trying to display a simple dynamic form using ember.js, im pretty new to ember and front-end frameworks in general.

I am using

  • Ember : 2.0.0
  • Ember Data : 2.0.0-beta.1
  • jQuery : 1.11.3
  • ember-cli : 1.13.6

The JSON payload is the following: some fields are to be generated and some elements have to be enabled.

JSON:

{
    "create-fields": [{
        "id": 1,
        "field": "widgetName",
        "label": "Widget Name",
        "tooltip": "Widget Name",
        "category": "textfield",
        "url": "",
        "required": true,
        "widgetform_id": 1
    }, {
        "id": 2,
        "field": "APIKey",
        "label": "API Key",
        "tooltip": "API Key",
        "category": "textfield",
        "url": "",
        "required": true,
        "widgetform_id": 1
    }, {
        "id": 3,
        "field": "Campaign",
        "label": "Select Campaign",
        "tooltip": "Select Campaign",
        "category": "select",
        "url": "campaigns/",
        "required": false,
        "widgetform_id": 1
    }, {
        "id": 4,
        "field": "checkbox",
        "label": "Sample Checkbox",
        "tooltip": "Sample Checkbox",
        "category": "checkbox",
        "url": "",
        "required": false,
        "widgetform_id": 1
    }],
    "enable-fields": [{
        "id": 1,
        "field": "showAdvanced",
        "required": false,
        "widgetform_id": 1
    }, {
        "id": 2,
        "field": "notification",
        "required": false,
        "widgetform_id": 1
    }, {
        "id": 3,
        "field": "enableNotif",
        "required": false,
        "widgetform_id": 1
    }, {
        "id": 4,
        "field": "email",
        "required": false,
        "widgetform_id": 1
    }, {
        "id": 5,
        "field": "phone",
        "required": false,
        "widgetform_id": 1
    }, {
        "id": 6,
        "field": "reqType",
        "required": false,
        "widgetform_id": 1
    }, {
        "id": 7,
        "field": "dataFormat",
        "required": false,
        "widgetform_id": 1
    }, {
        "id": 8,
        "field": "appendUrlParams",
        "required": false,
        "widgetform_id": 1
    }],
    "widgetforms": [{
        "id": 1,
        "formname": "Edit Widget",
        "enable-field_ids": [1, 2, 3, 4, 5, 6, 7, 8],
        "create-field_ids": [1, 2, 3, 4]
    }]
}

//models

widgetform.js:

import DS from 'ember-data';

export default DS.Model.extend({
    formname: DS.attr(),
    createFields: DS.hasMany('createFields'),
    enableFields: DS.hasMany('enableFields')
});

create-field.js:

import DS from 'ember-data';

export default DS.Model.extend({
    field: DS.attr(),
    label: DS.attr(),
    tooltip: DS.attr(),
    category: DS.attr(),
    url: DS.attr('string', {defaultValue: ""}),
    required: DS.attr('boolean'),
    widgetform: DS.belongsTo('widgetform')
});

enable-field.js:

import DS from 'ember-data';

export default DS.Model.extend({
    field: DS.attr(),
    required: DS.attr('boolean'),
    widgetform: DS.belongsTo('widgetform')
});

template

widgetform.hbs: The hbs doesn't have all the fields it is just a mockup.

<div class="container-fluid">
{{#each model as |form|}}
<form class="form-horizontal">
<fieldset>
<header id="header">
  <h1>{{form.formname}}</h1>
</header>
<section id="main">
    <ul id="field-list">
        {{form.createFields}}
        {{#each form.createFields as |element|}}
            <li>test1  {{element.field}}</li>
        {{/each}}
    </ul>
</section>
</fieldset>
</form>
{{/each}}
</div>    

So far I've been able to see the data in the respective models using ember-inspector in chrome.

However, in the template when using the {{form.createFields}} I get a <DS.PromiseManyArray>, and the {{form.createFields.content}} is a <DS.ManyArray> object both of which I couldn't iterate through.

The test1 that I put in the template is not printing in the page. The {{form.formname}} property however is available and is printed in the page.

I've checked many questions like this, and the general suggestion is to add the id list but I've added them in the JSON but I don't see the difference

screenshot of ember-inspector data tab: enter image description here

What am I doing wrong here? Any ideas?


Solution

  • For some reason the RESTAdapter was not working for this particular data set or environment, so I decided to scrap it and embrace the new JSONAPI 1.0 specs and use the JSONAPIAdapter.

    Models:

    create-field.js:

    import DS from 'ember-data';
    
    export default DS.Model.extend({
        field: DS.attr(),
        label: DS.attr(),
        tooltip: DS.attr(),
        category: DS.attr(),
        url: DS.attr('string', { defaultValue: ""}),
        required: DS.attr('boolean')
    });
    

    enable-field.js

    import DS from 'ember-data';
    
    export default DS.Model.extend({
        field: DS.attr(),
        required: DS.attr('boolean')
    });
    

    widgetform.js

    import DS from 'ember-data';
    
    export default DS.Model.extend({
        formname: DS.attr(),
        createFields: DS.hasMany('create-field'),
        enableFields: DS.hasMany('enable-field')
    });
    

    The JSON for the above model is formatted as per the JSONAPI 1.0 spec: http://jsonapi.org/format/

    {
      "data": [{
        "type": "widgetform",
        "id": 1,
        "attributes": {
          "formname": "Edit Widget"
        },
        "relationships": {
          "create-fields": {
            "data": [{
              "type": "create-fields",
              "id": "1"
            }, {
              "type": "create-fields",
              "id": "2"
            }]
          },
          "enable-fields": {
            "data": [{
              "type": "enable-fields",
              "id": "1"
            }, {
              "type": "enable-fields",
              "id": "2"
            }]
          }
        }
      }],
      "included": [{
        "type": "create-fields",
        "id": "1",
        "attributes": {
          "field": "widgetName",
          "label": "Widget Name",
          "tooltip": "Widget Name",
          "category": "textfield",
          "required": true
        }
      }, {
        "type": "create-fields",
        "id": "2",
        "attributes": {
          "field": "APIKey",
          "label": "API Key",
          "tooltip": "API Key",
          "category": "textfield",
          "required": true
        }
      }, {
        "type": "enable-fields",
        "id": "1",
        "attributes": {
          "field": "showAdvanced",
          "required": false
        }
      }, {
        "type": "enable-fields",
        "id": "2",
        "attributes": {
          "field": "notification",
          "required": false
        }
      }]
    }
    

    adapter: application.js

    import DS from 'ember-data';
    
    export default DS.JSONAPIAdapter.extend({
        namespace: 'api'
    });
    

    And I was able to access it from the template using the each block as usual

    widgetform.hbs

    <div class="container-fluid">
    {{#each model as |form|}}
    <form class="form-horizontal">
    <fieldset>
    <header id="header">
      <h1>{{form.formname}}</h1>
    </header>
    <section id="main">
        <ul id="field-list">
            {{#each form.createFields as |element|}}
                <li>
                    <input name="{{element.field}}" type="text">
                </li>
            {{/each}}
          </ul>
    </section>
    </fieldset>
    </form>
    {{/each}}
    </div>
    

    I hope it helps someone...