You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何查找通过createRecord创建且ID为null的Ember-Data记录?

解决Ember 3.8中无ID记录的更新问题

针对你遇到的场景,我有几个实用的解决方案,优先推荐最贴合Ember数据流设计的方式:

方案一:直接将记录传递给表单组件(最简洁)

既然你的foo/add路由的model函数已经返回了通过createRecord创建的空foo记录,控制器会自动持有这条记录作为model属性。你只需要在模板里把这条记录直接传给表单组件,组件就能直接操作它,完全不需要“找记录”的步骤:

  1. 路由保持现有逻辑:
// 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');
  }
});
  1. 模板传递记录给组件:
{{! app/templates/foo/add.hbs }}
{{! 把路由返回的model直接传给表单组件 }}
{{foo-form foo=model}}
  1. 组件内直接更新记录:
    在表单组件的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钩子中把记录赋值给控制器的自定义属性,之后组件发送动作时,控制器直接用这个属性操作记录:

  1. 路由中把记录绑定到控制器:
// 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);
  }
});
  1. 组件发送动作传递选中值:
// 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')}}
  1. 控制器中更新记录:
// 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:34:41