Ember js - 与关系保存模型

时间:2018-03-18 14:52:29

标签: ember.js ember-data

我的服务器正在返回一个json数据,使用Ember Data加载模型(page.js,event.js,choice.js)没有问题。但是在提交表单时,提交给服务器的JSON数据不包含相关模型(event.js,choice.js)。

以下是我的文件和json数据。

后端api返回的Json数据:

{
   "data":    {
      "type": "pages",
      "id": "12345",
      "attributes":       {
         "guest_id": null,
         "name": null,
         "email": null,
         "address": null
      },
      "relationships": {"events": {"data":       [
                  {
            "type": "events",
            "id": "67891"
         },
                  {
            "type": "events",
            "id": "90908"
         }
      ]}}
   },
   "included":    [
            {
         "type": "events",
         "id": "67891",
         "attributes":          {
            "event_id": "67891",
            "name": "Event 1"
         },
         "relationships": {"choices": {"data":          [
                        {
               "type": "choices",
               "id": "67891-11111"
            },
                        {
               "type": "choices",
               "id": "67891-22222"
            }
         ]}}
      },
            {
         "type": "events",
         "id": "90908",
         "attributes":          {
            "event_id": "90908",
            "name": "Event 2"
         },
         "relationships": {"choices": {"data":          [
                        {
               "type": "choices",
               "id": "90908-11111"
            },
                        {
               "type": "choices",
               "id": "90908-22222"
            }
         ]}}
      },
            {
         "type": "choices",
         "id": "67891-11111",
         "attributes":          {
            "choice_id": "67891-11111",
            "name": "Diet choice",
            "value": "0"
         },
         "relationships": null
      },
            {
         "type": "choices",
         "id": "",
         "attributes":          {
            "choice_id": "67891-22222",
            "name": "No. of adult guest",
            "value": "0"
         },
         "relationships": null
      }
            {
         "type": "choices",
         "id": "90908-11111",
         "attributes":          {
            "choice_id": "90908-11111",
            "name": "Diet choice",
            "value": "0"
         },
         "relationships": null
      },
            {
         "type": "choices",
         "id": "90908-22222",
         "attributes":          {
            "choice_id": "90908-22222",
            "name": "No. of adult guest",
            "value": "0"
         },
         "relationships": null
      }
   ]
}

提交给服务器的JSON数据

    {
        "data": {
            "id":"e47e8358-0f18-4607-b958-2877155bf5be",
            "attributes":{
                "guest_id":null,
                "name":"my name",
                "email":"myemail@gmail.com",
                "address":"myaddress"
            },
            "relationships":{
                "events":{
                    "data":[
                        {
                            "type":"events",
                            "id":"67891"
                        },
                        {
                            "type":"events",
                            "id":"90908"
                        }
                    ]
                }
            },
            "type":"pages"
        } 
}

/pages/show.hbs

<p>
    <label>Name: </label>
    {{input type="text" value=model.name id="name"}}
</p>

{{#each model.events as |event|}}
    <h3>
        {{event.name}}
        <!-- Rounded switch -->
        <label class="switch">
          <input type="checkbox" class="switch_input" id="{{event.id}}">
          <span class="slider round"></span>
        </label>
    </h3>

    {{#each event.choices as |choice|}}
        {{#if (is-equal choice.name "Diet choice")}}
            <p>
                <label for="diet_choice">{{choice.name}}:</label>
                <select id="diet_choice" value=choice.value>
                    <option value="anything">Anything and Everything</option>
                    <option value="vegetarian">Vegetarian</option>
                    <option value="hala">Hala</option>
                </select>
            </p>
        {{/if}}
        {{#if (is-equal choice.name "No. of adult guest")}}
            <p>
                Adult guest
                <div>
                    <button type="button" name="btnMinusGuest" {{action "minusCounter" choice 0 "Minimum 0 guest"}}>-</button>
                    {{input type="text" value=choice.value}}
                    <button type="button" name="btnPlusGuest" {{action "addCounter" choice 1 "Maximum 1 guest"}}>+</button>
                </div>
            </p>
        {{/if}}
    {{/each}}
{{/each}}

<p>
    <label for="email">Email:</label>
    {{input type="text" value=model.email}}
</p>
<p>
    <label for="address">Address:</label>
    {{input type="text" value=model.address}}
</p>
<p>
    <input type="submit" name="btnSubmit" value="Submit" {{action "submit"}} />
    <input type="submit" name="btnCancel" value="Cancel" {{action "cancel"}} />
</p>
{{outlet}}

/routes/pages/show.js

import Route from '@ember/routing/route';

export default Route.extend({
    queryParams: {
        event: ''
    },
    model(params) {
        return this.get('store').findRecord('page', params.page_id, { adapterOptions: {query: {'event': params.event}}});
    },
    actions: {
        submit() {
            // Create rec
            page.save().then(function() {
                console.log('submitted');
            }).catch(function(reason) {
                console.log(reason);
            });
        },
        cancel() {
            alert("Are you sure?");
        },
        addCounter(item, max_val, msg) {
            let current_val = parseInt(item.get('value'));
            if (current_val >= max_val) {
                alert(msg)
            } else {
                item.set('value', current_val + 1);
            }
        },
        minusCounter(item, min_val, msg) {
            let current_val = parseInt(item.get('value'));
            if (current_val <= min_val) {
                alert(msg);
            } else {
                item.set('value', current_val - 1)
            }
        },
    }
});

/models/page.js

import DS from 'ember-data';

export default DS.Model.extend({
    guest_id: DS.attr(),
    name: DS.attr(),
    email: DS.attr(),
    address: DS.attr(),
    is_e_invite: DS.attr(),
    data_time_submitted: DS.attr(),
    events: DS.hasMany('event')
});

/models/event.js

import DS from 'ember-data';

export default DS.Model.extend({
    event_id: DS.attr(),
    name: DS.attr(),
    choices: DS.hasMany('choice')
});

/models/choice.js

import DS from 'ember-data';

export default DS.Model.extend({
    choice_id: DS.attr(),
    name: DS.attr(),
    value: DS.attr()
});

1 个答案:

答案 0 :(得分:0)

解决问题的一种方法是独立保存每个模型,正如@Lux在评论中所说的那样,但您也可以编写一个自定义序列化程序,它将在保存父模型后半手动准备要推送的数据。

假设您正在使用ember-data,它应该看起来像这样(请参阅https://guides.emberjs.com/v3.0.0/models/customizing-serializers/):

创建一个名为serializers/page.js的文件并放在那里:

import DS from 'ember-data';

export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {

    attrs: {
        events: {embedded: 'save'}
    },

    serializeIntoHash: function (data, type, record, options) {
        const object = this.serialize(record, options);
        for (let key in object) {
            data[key] = object[key];
        }
    },

    serializeHasMany: function (record, json, relationship) {
        const key = relationship.key;
        const hasManyRecords = record.hasMany(key);

        if (!hasManyRecords || !this.attrs[key] || this.attrs[key].embedded !== 'save') {
            return this._super(record, json, relationship);
        }

        json[key] = [];

        hasManyRecords.forEach(item => {

            let recordData = item.serialize({includeId: true});

            if (relationship.options.deepEmbedded) {
                relationship.options.deepEmbedded.forEach(deepKey => {

                    if (!item.hasMany(deepKey)) {
                        return true;
                    }

                    const deepRecords = item.hasMany(deepKey);

                    recordData[deepKey] = [];

                    deepRecords.forEach(deepRecord => {
                        recordData[deepKey].push(deepRecord.serialize({includeId: true}));
                    });
                });
            }

            json[key].push(recordData);
        });
    }
});

并在page模型中将events: DS.hasMany('event')更改为events: DS.hasMany('event', {deepEmbedded: ['choices']})

以上序列化程序告诉ember-dataevent的{​​{1}}作为序列化地图放入page的输出地图中。此外,对于每个page,它还会遍历关系的每个event模型 - 在这种情况下为deepEmbedded - 并且还会序列化它们。

注意:choices选项不属于deepEmbedded,我是根据我的特定需求创建的,因此在每种情况下都可能无法正常运行。