EmberJS 2.7 = has_many Ember-Data 和活动模型序列化程序的配置,使用 Ember-Power-Select (和侧面加载,而不是嵌入数据)
EmberJS 2.7 = has_many configuration for Ember-Data and Active Model Serializers, using Ember-Power-Select (and side loaded, not embedded data)
这是一个与 this one 类似的问题,不同之处在于这是针对 Ember 和 Active Model Serializers (0.10.2) 的最新版本。
我有一段简单的 Parent:Child 关系。
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')}`;
}),
});
当我创建一个新的 Trail,并且 select 两名员工为 'hasMany' 时,以下 json 到达 服务器(来自Rails 日志):
{"data":
{"attributes":
{"name":"TEST3",
"gpx-file-url":"a url",
"distance-value":"5"},
"relationships":
{"employees":{"data":[]}}, "type":"trails"}}
我的问题是,员工怎么了?员工的 ID 在哪里(他们已经存在于数据库和 Ember 商店中 - 即,我没有尝试在此请求中创建 child 记录)。
编辑
我刚发现 this 问题,它解释了 hasMany 关系的 ID 不是由 Ember 的 JSONAPISerializer 发送到 API - 因为这里的外键实际上必须保留在每个 child 记录中。因此,基本上 'selecting' 名员工,您需要保存他们现在拥有 parent 个事实。所以 selected 员工记录需要持久化。
但我的理解是这一切都有效 "out of the box" 并且 Ember 会自动触发 POST 请求来执行此操作,但情况似乎并非如此。
这就进入了真正的问题 - 我如何更新那些 children?
更新 - 由于这个问题已经发展,所以增加了赏金
经过进一步分析,很明显需要一个新模型 - Assignments。所以现在的问题比较复杂。
模型结构现在是这样的:
踪迹
有许多作业
员工
有许多作业
作业
属于步道
属于员工
在我的'new Trail'路线中,我使用奇妙的ember-power-select让用户select员工。单击 'save' 后,我计划遍历 selected 员工,然后创建分配记录(显然保存它们,在保存 Trail 本身之前或之后,不确定哪个是最好的)。
但是,问题仍然存在,我不知道该怎么做 - 如何找到 'selected' 员工,然后遍历他们以创建分配。
所以,这是我模板中的相关 EPS 用法:
在/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 是来自 Dockyard 的助手,它会自动将动作发送到我的路线,效果很好)
这是我的模型:
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);
},
}
我今天才发现我们还需要控制器,所以这可能是我的问题!这是:
import Ember from 'ember';
export default Ember.Controller.extend({
staff: [] <- I guess this needs to be something more complicated
});
这有效,我看到一个 object 被添加到控制台的数组中。但是 EPS 拒绝工作,因为我在控制台中收到此错误:
trekclient.js:91 Uncaught TypeError: Cannot read property 'toString' of undefined(anonymous function) @ trekclient.js:91ComputedPropertyPrototype.get @ vendor.js:29285get @
etc....
紧随其后的是:
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]
所以我想这是因为文档中的示例只使用了一个包含字符串的数组,而不是实际的 Ember.Objects。但是我不知道如何解决这个问题。
所以,我决定扔掉控制器(哈哈),发挥创意。
如果我在 Trail 模型中添加一个 属性 会怎么样?这个 属性 基本上可以是 'dummy' 属性 收集了 selected 员工。
在/app/models/trail.js
selectedEmps: DS.hasMany('employee', async {false})
我将 async 设置为 false,因为我们不会保留它们,在保存新 Trail 之前,我可以再次将其设置为 null。
在/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}}
这行得通,但在 select 第一个员工之后 'blow up' 行不通。我可以 select 多个并从模板中删除它们。该控件似乎工作正常,因为它正在直接变异 'model.selectedEmps'。
现在,我认为这是一个 hack,因为我有两个问题:
- 如果我将 'mut' 更改为一个动作,这样我就可以添加更多的逻辑,我
无法弄清楚如何访问实际存储在
属性'model.selectedEmps'
- 即使我能弄清楚 (1) 我也必须始终确保
'selectedEmps'离开这条路线时清空,否则
下次进入这条路线时,它会记住之前的内容
select之前编辑过(因为它们现在在 Ember.Store)
根本问题是我可以接受 'mut' 但仍然有问题,当用户点击 'Save' 时,我必须弄清楚哪些员工被 selected,所以我可以为他们创建作业。
但我不知道如何访问 selected 的内容。也许这 Spaghetti-Monster-awful 一团糟:
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.");
}
},
所以有两个问题需要解决:
- 如何获得 selected 员工,迭代并创建
作业。
- 如何将结果保存到API(JSON-API 使用Rails)。我
假设
newObj.save
和 each assignment.save
会照顾
那个
更新
EPS 的开发者友善地指出动作处理程序接收一个数组,因为我改为使用多个 select,而不是像以前那样使用单个 select。因此,该操作正在接收当前 selected 的完整数组。卫生署!
因此,我能够按如下方式更新操作处理程序,它现在成功地将当前 selected 员工存储在控制器的员工 属性 中。更近一步。
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
}
});
}
也许这不是将 2 个数组相交的最佳方法,但这是我周六晚上凌晨 4 点最不关心的问题。 :(
最后的问题更新 - 如何保存数据?
好的,现在我可以获得 selected 员工,我可以创建分配,但仍然无法弄清楚 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('assignments').save().then(function() {
console.log('DONE');
});
});
}
get(...).save is not a function
最后一次更新的问题是,在 Ember 数据 2.x 中,关系默认是异步的,因此从 newTrail.get('assignments')
返回的不是 DS.ManyArray
,其中有 .save
,但 PromiseArray
没有。
您需要进行一些小的调整才能执行此操作,因此您在已解决的关系上调用 .save
:
newObject.save().then(function (newTrail) {
newTrail.get('assignments').then(assignments => assignments.save()).then(function() {
console.log('DONE');
});
});
这是一个与 this one 类似的问题,不同之处在于这是针对 Ember 和 Active Model Serializers (0.10.2) 的最新版本。
我有一段简单的 Parent:Child 关系。
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')}`;
}),
});
当我创建一个新的 Trail,并且 select 两名员工为 'hasMany' 时,以下 json 到达 服务器(来自Rails 日志):
{"data":
{"attributes":
{"name":"TEST3",
"gpx-file-url":"a url",
"distance-value":"5"},
"relationships":
{"employees":{"data":[]}}, "type":"trails"}}
我的问题是,员工怎么了?员工的 ID 在哪里(他们已经存在于数据库和 Ember 商店中 - 即,我没有尝试在此请求中创建 child 记录)。
编辑
我刚发现 this 问题,它解释了 hasMany 关系的 ID 不是由 Ember 的 JSONAPISerializer 发送到 API - 因为这里的外键实际上必须保留在每个 child 记录中。因此,基本上 'selecting' 名员工,您需要保存他们现在拥有 parent 个事实。所以 selected 员工记录需要持久化。
但我的理解是这一切都有效 "out of the box" 并且 Ember 会自动触发 POST 请求来执行此操作,但情况似乎并非如此。
这就进入了真正的问题 - 我如何更新那些 children?
更新 - 由于这个问题已经发展,所以增加了赏金
经过进一步分析,很明显需要一个新模型 - Assignments。所以现在的问题比较复杂。
模型结构现在是这样的:
踪迹
有许多作业
员工
有许多作业
作业
属于步道
属于员工
在我的'new Trail'路线中,我使用奇妙的ember-power-select让用户select员工。单击 'save' 后,我计划遍历 selected 员工,然后创建分配记录(显然保存它们,在保存 Trail 本身之前或之后,不确定哪个是最好的)。
但是,问题仍然存在,我不知道该怎么做 - 如何找到 'selected' 员工,然后遍历他们以创建分配。
所以,这是我模板中的相关 EPS 用法:
在/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 是来自 Dockyard 的助手,它会自动将动作发送到我的路线,效果很好)
这是我的模型:
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);
},
}
我今天才发现我们还需要控制器,所以这可能是我的问题!这是:
import Ember from 'ember';
export default Ember.Controller.extend({
staff: [] <- I guess this needs to be something more complicated
});
这有效,我看到一个 object 被添加到控制台的数组中。但是 EPS 拒绝工作,因为我在控制台中收到此错误:
trekclient.js:91 Uncaught TypeError: Cannot read property 'toString' of undefined(anonymous function) @ trekclient.js:91ComputedPropertyPrototype.get @ vendor.js:29285get @
etc....
紧随其后的是:
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]
所以我想这是因为文档中的示例只使用了一个包含字符串的数组,而不是实际的 Ember.Objects。但是我不知道如何解决这个问题。
所以,我决定扔掉控制器(哈哈),发挥创意。
如果我在 Trail 模型中添加一个 属性 会怎么样?这个 属性 基本上可以是 'dummy' 属性 收集了 selected 员工。
在/app/models/trail.js
selectedEmps: DS.hasMany('employee', async {false})
我将 async 设置为 false,因为我们不会保留它们,在保存新 Trail 之前,我可以再次将其设置为 null。
在/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}}
这行得通,但在 select 第一个员工之后 'blow up' 行不通。我可以 select 多个并从模板中删除它们。该控件似乎工作正常,因为它正在直接变异 'model.selectedEmps'。
现在,我认为这是一个 hack,因为我有两个问题:
- 如果我将 'mut' 更改为一个动作,这样我就可以添加更多的逻辑,我 无法弄清楚如何访问实际存储在 属性'model.selectedEmps'
- 即使我能弄清楚 (1) 我也必须始终确保 'selectedEmps'离开这条路线时清空,否则 下次进入这条路线时,它会记住之前的内容 select之前编辑过(因为它们现在在 Ember.Store)
根本问题是我可以接受 'mut' 但仍然有问题,当用户点击 'Save' 时,我必须弄清楚哪些员工被 selected,所以我可以为他们创建作业。
但我不知道如何访问 selected 的内容。也许这 Spaghetti-Monster-awful 一团糟:
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.");
}
},
所以有两个问题需要解决:
- 如何获得 selected 员工,迭代并创建 作业。
- 如何将结果保存到API(JSON-API 使用Rails)。我
假设
newObj.save
和each assignment.save
会照顾 那个
更新
EPS 的开发者友善地指出动作处理程序接收一个数组,因为我改为使用多个 select,而不是像以前那样使用单个 select。因此,该操作正在接收当前 selected 的完整数组。卫生署!
因此,我能够按如下方式更新操作处理程序,它现在成功地将当前 selected 员工存储在控制器的员工 属性 中。更近一步。
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
}
});
}
也许这不是将 2 个数组相交的最佳方法,但这是我周六晚上凌晨 4 点最不关心的问题。 :(
最后的问题更新 - 如何保存数据?
好的,现在我可以获得 selected 员工,我可以创建分配,但仍然无法弄清楚 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('assignments').save().then(function() {
console.log('DONE');
});
});
}
get(...).save is not a function
最后一次更新的问题是,在 Ember 数据 2.x 中,关系默认是异步的,因此从 newTrail.get('assignments')
返回的不是 DS.ManyArray
,其中有 .save
,但 PromiseArray
没有。
您需要进行一些小的调整才能执行此操作,因此您在已解决的关系上调用 .save
:
newObject.save().then(function (newTrail) {
newTrail.get('assignments').then(assignments => assignments.save()).then(function() {
console.log('DONE');
});
});