如何在Ember中通过Model在页面间传递数据?现有方法数据丢失
在Ember中通过Model跨页面传递数据的正确实践
首先得先帮你排查下现有代码可能导致数据丢失的几个问题:
- 你的
combineArray计算属性没有设置依赖项,它只会执行一次。如果model.ccList或者关联的cardtransactions是异步加载的,计算属性会在数据还没完全加载时就执行,自然会丢数据。 - 直接给Ember Data Model动态添加
processedTrans属性是不规范的——ED的Model是基于预定义Schema的,未声明的属性不会被Ember的追踪系统监控,也可能在页面跳转时丢失。 - 用
JSON.parse(JSON.stringify(transaction))这种粗暴的序列化方式,会丢失ED Model实例的追踪属性,甚至遗漏未加载的关联数据,这也是部分数据丢失的核心原因之一。
接下来给你一套正确的实现方案,完全符合你“通过更新Model传递数据”的需求:
1. 先在Model类中声明自定义属性
首先要在你的目标Model(比如对应的订单/账户Model)里,显式声明processedTrans属性,让Ember Data能正确追踪它:
// app/models/your-model.js import Model, { attr, hasMany } from '@ember-data/model'; export default class YourModel extends Model { @hasMany('cc') ccList; // 假设这是你原有的关联属性 @attr('array') processedTrans; // 声明数组类型的自定义属性 }
2. 修正计算属性的实现
调整计算逻辑,添加正确的依赖项,并用ED官方的方式处理Model数据:
combineArray: Ember.computed('model.ccList.@each.cardtransactions.[]', function() { const trans = Ember.A(); const that = this; // 用forEach代替map(我们不需要返回新数组,只是遍历处理) this.get('model.ccList').forEach(card => { const cardName = card.get('cardName'); const cardNum = card.get('cardNum'); card.get('cardtransactions').forEach(transaction => { // 用ED的toJSON()方法序列化Model,避免丢失数据 const transactionData = transaction.toJSON(); const temp = { ...transactionData, cardName, cardNum, selected: false, handlingFee: that.setHandlingFee(transaction.get('localCurrencyAmount')) }; // 直接创建Ember对象并加入数组 trans.push(Ember.Object.create(temp)); }); }); // 用set方法设置Model属性,确保Ember追踪变化 this.set('model.processedTrans', trans); console.log(this.get('model.processedTrans.firstObject')); return this.get('model.processedTrans'); }),
这里的关键改进:
- 依赖项
model.ccList.@each.cardtransactions.[]确保当任何卡片的交易列表变化时,计算属性会重新执行 - 用
transaction.toJSON()代替粗暴的JSON序列化,完整保留Model的已加载数据 - 用
set方法更新Model属性,触发Ember的响应式更新
3. 确保异步数据预加载
如果cardtransactions是异步关联,一定要在路由的model钩子中预加载所有数据,避免计算属性执行时数据还没加载完成:
// app/routes/your-current-page.js import Route from '@ember/routing/route'; export default class YourCurrentPageRoute extends Route { async model() { const model = await this.store.findRecord('your-model', 'target-id'); // 预加载所有卡片的交易数据 await Promise.all( model.get('ccList').map(card => card.get('cardtransactions')) ); return model; } }
4. 跨页面传递Model的正确方式
在跳转页面时,直接传递Model实例即可,Ember会自动维护实例的状态:
// 在控制器或组件中触发跳转 this.transitionTo('next-page', this.get('model'));
然后在目标路由中接收这个Model:
// app/routes/next-page.js import Route from '@ember/routing/route'; export default class NextPageRoute extends Route { model(params, transition) { // 直接获取传递过来的Model实例 return transition.to.model; } }
这样目标页面的控制器和模板就能直接使用model.processedTrans,所有更新的属性都会完整保留。
内容的提问来源于stack exchange,提问作者3gwebtrain
相关产品推荐
相关产品推荐

