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

Ember中model.pushObject未定义及push后UI不更新问题

Ember待办列表问题解决方案

问题原因分析

  1. model.pushObject is not a function报错:你的@model是普通JavaScript数组,pushObject是Ember内置MutableArray(如Ember.A()创建的数组)专属方法,普通数组不支持这个API,因此报错。
  2. 用push添加元素后UI不更新:Ember的自动追踪机制对普通数组只检测引用变化,原地修改数组(push、splice等操作)不会改变数组引用,UI无法感知内容变化,所以不会同步更新。

具体解决方法

方案一:使用Ember可追踪数组(推荐)

将数据源转换成Ember的MutableArray,这类数组的修改方法(pushObject、removeObject等)会自动触发UI更新:

  1. 在父组件/路由初始化数据时,用Ember.A()包装数组:
import { A } from '@ember/array';

// 示例:路由里设置model
export default class TodosRoute extends Route {
  model() {
    return A([{ id: 1, title: '初始待办' }]);
  }
}
  1. 组件内的submit方法直接使用pushObject:
@action
submit(model, event) {
  event.preventDefault();
  const lastId = model.length > 0 ? model[model.length - 1].id : 0;
  const newTodo = {
    id: lastId + 1,
    title: this.text
  };
  model.pushObject(newTodo);
  this.text = ''; // 清空输入框
}
  1. 删除方法改用removeObject:
@action
delete(model, item) {
  model.removeObject(item);
}

方案二:保持普通数组,通过替换引用触发更新

如果坚持使用普通数组,需要通过创建新数组替换原引用来触发Ember的追踪更新,同时遵循Ember数据流向(子组件不直接修改父组件数据,通过action通知父组件更新):

  1. 父组件定义数据和更新action:
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';

export default class ParentComponent extends Component {
  @tracked todos = [{ id: 1, title: '初始待办' }];

  @action
  addTodo(newTodo) {
    // 创建新数组替换原引用,触发UI更新
    this.todos = [...this.todos, newTodo];
  }

  @action
  removeTodo(item) {
    this.todos = this.todos.filter(todo => todo.id !== item.id);
  }
}
  1. 子组件模板传递action,不再直接传递model:
<ul class="hand">
  {{#each @todos as |item|}}
    <li>{{item.title}}</li>
    <button onclick={{fn this.removeTodo item}} type='button'>delete</button>
  {{/each}}
</ul>
<form onsubmit={{fn this.submit}}>
  <Input placeholder='Add todo' type='text' value={{this.text}} 
    onchange={{fn this.onChange}} />
  <button type='submit'>Add</button>
</form>
  1. 子组件内调用父组件的action:
@tracked text = "";

@action
submit(event) {
  event.preventDefault();
  const lastId = this.args.todos.length > 0 ? this.args.todos[this.args.todos.length - 1].id : 0;
  const newTodo = {
    id: lastId + 1,
    title: this.text
  };
  this.args.addTodo(newTodo);
  this.text = '';
}

@action
onChange(e) {
  this.text = e.target.value;
}

@action
removeTodo(item) {
  this.args.removeTodo(item);
}

额外注意点

  • 不要直接修改子组件接收的@model(外部传递的属性),遵循「数据向下传,动作向上发」的单向数据流原则,避免数据状态混乱。
  • 普通对象不需要用Ember的set方法修改属性,直接赋值即可(更推荐用filter创建新数组的方式删除元素)。

内容的提问来源于stack exchange,提问作者star lord

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 23:08:15