如何查找通过createRecord创建且ID为null的Ember-Data记录?
解决Ember 3.8中无ID记录的更新问题
针对你遇到的场景,我有几个实用的解决方案,优先推荐最贴合Ember数据流设计的方式:
方案一:直接将记录传递给表单组件(最简洁)
既然你的foo/add路由的model函数已经返回了通过createRecord创建的空foo记录,控制器会自动持有这条记录作为model属性。你只需要在模板里把这条记录直接传给表单组件,组件就能直接操作它,完全不需要“找记录”的步骤:
- 路由保持现有逻辑:
// app/routes/foo/add.js import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; export default Route.extend({ store: service(), model() { // 创建空记录并返回,控制器会自动拿到这个model return this.store.createRecord('foo'); } });
- 模板传递记录给组件:
{{! app/templates/foo/add.hbs }} {{! 把路由返回的model直接传给表单组件 }} {{foo-form foo=model}}
- 组件内直接更新记录:
在表单组件的onchange处理器里,直接操作传入的foo记录即可:
// app/components/foo-form.js import Component from '@ember/component'; export default Component.extend({ actions: { handleSelectChange(selectedOption) { // 直接更新传入的foo记录的对应属性 this.set('foo.targetProperty', selectedOption); } } });
组件模板里绑定power-select的onchange到这个动作:
{{! app/templates/components/foo-form.hbs }} {{#power-select options=yourOptionsList selected=foo.targetProperty onchange=(action 'handleSelectChange') as |option|}} {{option.displayText}} {{/power-select}}
这个方案完全贴合Ember“数据向下传递、动作向上冒泡”的设计理念,代码最简洁,也避免了无ID记录查找的麻烦。
方案二:通过控制器持有记录并接收动作更新
如果你更倾向于让控制器来处理记录更新,可以在路由的setupController钩子中把记录赋值给控制器的自定义属性,之后组件发送动作时,控制器直接用这个属性操作记录:
- 路由中把记录绑定到控制器:
// app/routes/foo/add.js import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; export default Route.extend({ store: service(), model() { return this.store.createRecord('foo'); }, setupController(controller, model) { this._super(controller, model); // 把创建的记录存到控制器的newFoo属性里 controller.set('newFoo', model); } });
- 组件发送动作传递选中值:
// app/components/foo-form.js import Component from '@ember/component'; export default Component.extend({ actions: { handleSelectChange(selectedOption) { // 把选中值通过动作传递给控制器 this.sendAction('updateFooProperty', selectedOption); } } });
模板里绑定动作:
{{! app/templates/foo/add.hbs }} {{foo-form updateFooProperty=(action 'updateFoo')}}
- 控制器中更新记录:
// app/controllers/foo/add.js import Controller from '@ember/controller'; export default Controller.extend({ actions: { updateFoo(selectedOption) { // 直接用控制器持有的newFoo记录更新属性 this.get('newFoo').set('targetProperty', selectedOption); } } });
可选方案:手动生成客户端ID
如果你确实需要通过ID在store中查找记录(比如跨组件共享记录的场景),可以在createRecord时手动生成一个唯一的客户端ID——因为你不需要和服务器通信,完全可以自己控制ID:
// 在路由的model函数中 model() { // 用时间戳生成唯一ID,避免冲突 const clientId = `foo-${Date.now()}`; return this.store.createRecord('foo', { id: clientId }); }
之后你就可以通过this.store.findRecord('foo', clientId)在任何地方找到这条记录了。不过这个方案其实没必要,除非你有特殊的跨组件共享需求,否则前两个方案更高效。
注意:因为你只在客户端使用store,这些记录只会存在内存中,页面刷新后会丢失,如果需要持久化,可以考虑用
localStorage配合Ember Data的适配器来实现客户端存储。
内容的提问来源于stack exchange,提问作者shearichard
相关产品推荐
相关产品推荐

