EmberJS 2.7 =使用Ember-Power-Select(和侧面加载,不嵌入数据)的Ember-Data和Active Model Serializers的has_many配置 [英] EmberJS 2.7 = has_many configuration for Ember-Data and Active Model Serializers, using Ember-Power-Select (and side loaded, not embedded data)

查看:635
本文介绍了EmberJS 2.7 =使用Ember-Power-Select(和侧面加载,不嵌入数据)的Ember-Data和Active Model Serializers的has_many配置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是类似于,除了这是最新版本的Ember和Active Model Serializers(0.10.2)。



我有一个简单的父母:孩子的关系。



app / models / trail.js

 从ember导入Ember; 
从ember-data导入DS;

导出默认DS.Model.extend({
名称:DS.attr(),

//关系
员工:DS.hasMany 'employee',{async:true}),

});

app / models / employee.js

 从ember-data导入DS; 

import来自'../models/person'的人

导出默认Person.extend({
status:DS.attr(),
statusCode:DS.attr(),
});

app / models / person.js

 从ember导入Ember; 
从ember-data导入DS;

导出默认DS.Model.extend({
avatarUrl:DS.attr(),
firstName:DS.attr(),
lastName:DS.attr (),

fullName:Ember.computed('firstName','lastName',function(){
return`$ {this.get('lastName')},$ {this .get('firstName')}`;
}),
});

当我创建一个新的Trail,并为'hasMany'选择两个员工时,以下json 到达服务器(从Rails日志):

  {data:
{ 属性:
{name:TEST3,
gpx-file-url:a url,
distance-value:5},
relationship:
{employees:{data:[]}},type:trails}}

我的问题是,员工发生了什么事?员工的身份证号码(他们已经存在于数据库和Ember Store中,即我没有在此请求中创建子记录)。



编辑



我刚刚发现这个问题,这解释说,一个hasMany关系的id不是由Ember的JSONAPISerializer发送到API - 因为这里的外键实际上必须在每个孩子中保留记录。所以基本上通过选择员工,你需要保存现在他们有一个父母的事实。所以选择的员工记录需要持久化。



但我的理解是,这一切都是开箱即用,Ember会自动触发POST请求来执行此操作,但似乎不是这样



这样就可以得到真正的问题 - 如何更新这些孩子?






更新 - 根据此问题已经增加了BOUNTY已更新






经过进一步分析,显然需要一个新的模型 - 作业。所以现在问题比较复杂。



现在的模型结构是这样的:






足迹



hasMany assignment






员工



hasMany assignment






作业



belongsTo Trail



belongsTo Employee






在我的新足迹路线中,我使用了梦幻般的 ember-power-select 让用户选择员工。点击保存,我计划迭代所选的员工,然后创建作业记录(显然,保存它们之前或之后保存Trail本身,不知道哪个是最好的)。



然而,问题仍然如此,我不知道该怎么做 - 如何获取选定的员工,然后再遍历他们创建作业。



所以,以下是我的模板中相关的EPS使用情况:



in / app / templates / trail /new.hbs

  {{#power-select-multiple options = model.currentEmployees 
searchPlaceholder =键入
searchField =fullName
selected = staff placeholder =选择团队成员
onchange =(route-action'staffSelected')as | employee |
}}
<块这里的模板显示各种员工数据,而不仅仅是'fullName'/>
{{/ power-select-multiple}}

(route-action是一个帮手从造船厂,只是自动发送行动到我的路线,工作伟大)



这是我的模型:

  model:function(){
let myFilter = {};
myFilter.data = {filter:{status:[2,3]}}; //当前员工
返回Ember.RSVP.hash({
trail:this.store.createRecord('trail'),
currentEmployees:this.store.query('employee',myFilter ).then(function(data){return data}),
});
},

actions:{
staffSelected(employee){
this.controller.get('staff')。pushObject(employee);
console.log(this.controller.get('staff')。length);
},
}

我今天才发现我们仍然需要控制器,所以这可能是我的问题!这里是:

 从ember导入Ember; 

export default Ember.Controller.extend({
staff:[]< - 我想这需要更复杂的东西
});

这个工作,我看到一个对象被添加到控制台中的数组。但是然后EPS拒绝工作,因为我在控制台中收到这个错误:

  trekclient.js:91未捕获TypeError:无法读取属性'toString'未定义(匿名函数)@ trekclient.js:91ComputedPropertyPrototype.get @ vendor.js:29285get @ 

etc ....
/ pre>

紧随其后的是:

 供应商。 js:16695 DEPRECATION:你修改(-join-classes(-normalize-classconcatenatedTriggerClassesconcatenatedTriggerClasses)ember-viewember-basic-dropdown-trigger(-normalize-classinPlaceClassinPlaceClass activeClass = undefined inactiveClass =未定义)(-normalize-classhPositionClasshPositionClass activeClass = undefined inactiveClass = undefined)(-normalize-classvPositionClassvPositionClass activeClass = undefined inactiveClass = undefined))在单个渲染中两次。这在Ember 1.x中是不可靠的,将在Ember 3.0中被删除[deprecation id:ember-views.render-double-modify] 

所以我想象这是因为文档中的示例只是使用一个包含字符串的数组,而不是实际的Ember.Objects。但是我不知道如何解决这个问题。



所以,我决定扔掉控制器(哈哈),并获得创意。



如果我向Trail模型添加了一个属性怎么办?该属性基本上可以是收集所选员工的虚拟属性。



在/app/models/trail.js中

  selectedEmps:DS.hasMany('employee',async {false})

我将异步设置为false,因为我们不会保留它们,并且在保存新路径之前,我可以将其重新设置为null。



/app/templates/trails/new.js

  {{#power-select-multiple options = model.currentEmployees 
searchPlaceholder =键入要搜索的名称
searchField =fullName
selected = model.selectedEmps placeholder =选择团队成员
onchange =(action(mut model。 selectedEmps))as | employee |
}}
< block here again />
{{/ power-select-multiple}}

选择第一名员工后,炸毁我可以选择多个并从模板中删除它们。控制似乎工作正常,因为它直接突变'model.selectedEmps'。



现在,我认为这是一个黑客,因为我有两个问题: / p>


  1. 如果我将'mut'更改为一个动作,那么我可以添加更多的逻辑,我
    无法弄清楚如何访问实际存储在
    中的实体'model.selectedEmps'

  2. 即使我可以弄清楚(1)我必须始终确保
    'selectedEmps在离开这条路线时被清空,否则下一次输入
    ,它会记住以前选择的
    (因为它们现在在Ember.Store中)

根本的问题是我可以使用'mut',但仍然有问题,当用户点击保存时,我必须弄清楚哪些员工被选中,所以我可以为他们创建任务。



但是我无法弄清楚如何访问所选内容。也许这个意大利面 - 怪物可怕的混乱:

  save:function(newObj){
console.log(newObj获得( 'selectedEmps'));
if(newObj.get('isValid')){
let emp = this.get('store')。createRecord('assignment',{
trail:newObj,
person:newObj.get('selectedEmps')[0]
})
newObj.save()然后(function(newTrail){
emp.save();
//newTrail.get('selectedEmps')
// this.transitionTo('trails');
console.log('DONE');
});
}
else {
alert(无效 - 请提供名称和GPX文件);
}
},

所以有两个问题需要解决: p>


  1. 如何获取所选员工,迭代并创建
    分配。

  2. 如何然后将结果保存到API(使用Rails的JSON-API)。 I
    假设 newObj.save 每个作业.save 将关注






更新






EPS的开发人员衷心指出,动作处理程序接收到一个数组,因为我改为使用多选,而不是单选早一点所以动作就是接收当前选择的全部数组。 DOH!



因此,我可以更新操作处理程序,如下所示,它现在将当前选定的员工成功存储在控制器的员工属性中。一步一步。

  staffSelected(newList){
existing.forEach(function(me){
if(!newList.includes(me)){
existing.removeObject(me); //如果我存在但是newList没有我,删除我
}
});
newList.forEach(function(me){
if(!existing.includes(me)){
existing.pushObject(me); //如果我不存在但是newList有我,加我
}
});
}

也许不是两个数组相交的最佳方法,但这是我最少的关注在星期六晚上4点。 :(






最终问题更新 - 如何保存数据?






好的,现在我可以获得选定的员工,我可以创建作业,但仍然无法弄清楚Ember需要什么来保存他们,这个保存动作会引发错误:

  save:function(newObject){
if(newObject.get 'isValid')){
let theChosenOnes = this.controller.get('theChosenOnes');
let _store = this.get('store');
theChosenOnes.forEach(function aChosenOne){
_store.createRecord('assignment',{
trail:newObject,
person:aChosenOne,
});
});
newObject.save()。then(function(newTrail){
newTrail.get('assignment')。save()。then(function(){
console.log('DONE');
});
});
}

get(...) .save不是一个函数


解决方案

更新是在Ember Data 2.x中,默认关系是异步的,所以从 newTrail.get('assignment')返回的不是 DS.ManyArray ,它有一个 .save ,但是一个 PromiseArray



您需要一个小的调整来做到这一点,所以你调用 .save 关系:

  newObject.save()。then(function(newTrail){
newTrail.get(' ).then(assignment => assignment.save())然后(function(){
console.log('DONE');
});
});


This is a similar question to this one, except this is for the latest versions of Ember and Active Model Serializers (0.10.2).

I have a simple Parent:Child relationship.

app/models/trail.js

import Ember from 'ember';
import DS from 'ember-data';

export default DS.Model.extend({
  name: DS.attr(),

  // relationships
  employees: DS.hasMany('employee', { async: true }),

});

app/models/employee.js

import DS from 'ember-data';

import Person from '../models/person';

export default Person.extend({
  status: DS.attr(),
  statusCode: DS.attr(),
});

app/models/person.js

import Ember from 'ember';
import DS from 'ember-data';

export default DS.Model.extend({
  avatarUrl: DS.attr(),
  firstName: DS.attr(),
  lastName: DS.attr(),

  fullName: Ember.computed('firstName', 'lastName', function() {
    return `${this.get('lastName')}, ${this.get('firstName')}`;
  }),
});

When I create a new Trail, and select two employees for the 'hasMany', the following json arrives the server (from the Rails log):

{"data":
  {"attributes":
    {"name":"TEST3", 
      "gpx-file-url":"a url", 
      "distance-value":"5"}, 
      "relationships":
         {"employees":{"data":[]}}, "type":"trails"}}

My question is, what has happened to the employees? Where are the id's of the employees (they already exist both in the database and in the Ember Store - ie, I am not trying to create child records in this request).

EDIT

I just found this question, which explains that the id's for a hasMany relationship are not sent by Ember's JSONAPISerializer to the API - since the foreign key here actually has to be persisted in each child record. So essentially by 'selecting' employees, you need to save the fact that they now have a parent. So the selected employee records need to be persisted.

But my understanding was that this all works "out of the box" and that Ember would automatically fire a POST request to do this, but that seems to not be the case.

This then gets to the real question - how do I update those children?


UPDATE - BOUNTY ADDED AS THIS HAS QUESTION HAS EVOLVED


After further analysis, it became clear that a new model was required - Assignments. So now the problem is more complex.

Model structure is now this:


Trail

hasMany assignments


Employee

hasMany assignments


Assignment

belongsTo Trail

belongsTo Employee


In my 'new Trail' route, I use the fantastic ember-power-select to let the user select employees. On clicking 'save' I plan to iterate through the selected employees and then create the assignment records (and obviously save them, either before or after saving the Trail itself, not sure which is best yet).

The problem is still, however, that I don't know how to do that - how to get at the 'selected' employees and then iterate through them to create the assignments.

So, here is the relevant EPS usage in my template:

in /app/templates/trails/new.hbs

  {{#power-select-multiple options=model.currentEmployees 
    searchPlaceholder="Type a name to search"
    searchField="fullName"
    selected=staff placeholder="Select team member(s)"
    onchange=(route-action 'staffSelected') as |employee| 
  }}
  <block here template to display various employee data, not just 'fullName'/>
  {{/power-select-multiple}}

(route-action is a helper from Dockyard that just automatically sends the action to my route, works great)

Here is my model:

  model: function () {
    let myFilter = {};
    myFilter.data = { filter: {status: [2,3] } }; // current employees
    return Ember.RSVP.hash({
      trail: this.store.createRecord('trail'),
      currentEmployees: this.store.query('employee', myFilter).then(function(data) {return data}),
    });
  },

  actions: {
    staffSelected (employee) {
      this.controller.get('staff').pushObject(employee);      
      console.log(this.controller.get('staff').length);
    },
  }

I only discovered today that we still need controllers, so this could be my problem! Here it is:

import Ember from 'ember';

export default Ember.Controller.extend({
  staff: [] <- I guess this needs to be something more complicated
});

This works and I see one object is added to the array in the console. But then the EPS refuses to work because I get this error in the console:

trekclient.js:91 Uncaught TypeError: Cannot read property 'toString' of undefined(anonymous function) @ trekclient.js:91ComputedPropertyPrototype.get @ vendor.js:29285get @ 

etc....

Which is immediately follow by this:

vendor.js:16695 DEPRECATION: You modified (-join-classes (-normalize-class "concatenatedTriggerClasses" concatenatedTriggerClasses) "ember-view" "ember-basic-dropdown-trigger" (-normalize-class "inPlaceClass" inPlaceClass activeClass=undefined inactiveClass=undefined) (-normalize-class "hPositionClass" hPositionClass activeClass=undefined inactiveClass=undefined) (-normalize-class "vPositionClass" vPositionClass activeClass=undefined inactiveClass=undefined)) twice in a single render. This was unreliable in Ember 1.x and will be removed in Ember 3.0 [deprecation id: ember-views.render-double-modify]

So I imagine this is because the examples in the documentation just uses an array containing strings, not actual Ember.Objects. But I have no clue how to solve this.

So, I decided to throw away the controller (ha ha) and get creative.

What if I added a property to the Trail model? This property can basically be a 'dummy' property that collected the selected employees.

in /app/models/trail.js

selectedEmps: DS.hasMany('employee', async {false}) 

I set async to false since we will not persist them and before saving the new Trail I can just set this to null again.

in /app/templates/trails/new.js

  {{#power-select-multiple options=model.currentEmployees 
    searchPlaceholder="Type a name to search"
    searchField="fullName"
    selected=model.selectedEmps placeholder="Select team member(s)"
    onchange=(action (mut model.selectedEmps)) as |employee| 
  }}
  <block here again/>
  {{/power-select-multiple}}

This works, it doesn't 'blow up' after selecting the first employee. I can select multiple and delete them from the template. The control seems to work fine, as it is mutating 'model.selectedEmps' directly.

Now, I think this is a hack because I have two problems with it:

  1. If I change the 'mut' to an action, so I can add further logic, I cannot figure out how to access what is actually stored in the propery 'model.selectedEmps'
  2. Even if I can figure out (1) I will have to always make sure that 'selectedEmps' is emptied when leaving this route, otherwise the next time this route is entered, it will remember what was selected before (since they are now in the Ember.Store)

The fundamental issue is that I can live with 'mut' but still have the problem that when the user hits 'Save' I have to figure out which employees were selected, so I can create the assignments for them.

But I cannot figure out how to access what is selected. Maybe something this Spaghetti-Monster-awful mess:

    save: function (newObj) {
      console.log(newObj.get('selectedEmps'));
      if (newObj.get('isValid')) {
        let emp = this.get('store').createRecord('assignment', {
          trail: newObj,
          person: newObj.get('selectedEmps')[0]
        })
        newObj.save().then( function (newTrail) {
            emp.save();
            //newTrail.get('selectedEmps')
 //         this.transitionTo('trails');
          console.log('DONE');
        }); 
      }
      else {
        alert("Not valid - please provide a name and a GPX file.");
      }
    },

So there are two problems to solve:

  1. How to get the selected employees, iterate and create the assignments.
  2. How to then save the results to the API (JSON-API using Rails). I presume that newObj.save and each assignment.save will take care of that.


UPDATE


The developer of EPS kindly pointed out that the action handler receives an array, since I changed to using a multiple select, not a single select as it had been earlier. So the action is receiving the full array of what is currently selected. DOH!

I was thus able to update the action handler as follows, which now successfully stores the currently selected employees in the staff property of the controller. One step closer.

  staffSelected(newList) {
      existing.forEach(function(me){
        if (!newList.includes(me)) {
          existing.removeObject(me); // if I exist but the newList doesn't have me, remove me
        }
      });
      newList.forEach(function(me){
        if (!existing.includes(me)) {
          existing.pushObject(me); // if I don't exist but the newList has me, add me
        }          
      });
  }

Perhaps not the best way to intersect 2 arrays but that's the least of my concerns at 4am on a Saturday night. :(


FINAL PROBLEM UPDATE - how to save the data?


Ok, so now that I can get the selected employees, I can create assignments, but still cannot figure out what Ember requires for me to save them, this save action throws an error:

save: function (newObject) {
      if (newObject.get('isValid')) {
        let theChosenOnes = this.controller.get('theChosenOnes');
        let _store = this.get('store');
        theChosenOnes.forEach(function (aChosenOne) {
          _store.createRecord('assignment', {
            trail: newObject,
            person: aChosenOne,
          });
        });
        newObject.save().then(function (newTrail) {
          newTrail.get('assignments').save().then(function() {
            console.log('DONE');
          });
        });
      }

get(...).save is not a function

解决方案

The problem with your final update is that in Ember Data 2.x, relationships are asynchronous by default, so what's returned from newTrail.get('assignments') is not a DS.ManyArray, which has a .save, but a PromiseArray, which doesn't have that.

You need a small tweak to do this instead, so you call .save on the resolved relationship:

newObject.save().then(function (newTrail) {
    newTrail.get('assignments').then(assignments => assignments.save()).then(function() {
        console.log('DONE');
    });
});

这篇关于EmberJS 2.7 =使用Ember-Power-Select(和侧面加载,不嵌入数据)的Ember-Data和Active Model Serializers的has_many配置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆