Ember中用服务替代查询参数:路由模型过滤失效问题
嘿,我明白你遇到的问题了——Ember的路由model钩子默认只会在首次进入路由时执行一次,当你切换到其他路由再返回时,Ember会直接复用之前已经加载好的模型数据,不会重新调用model钩子。所以当currentContract的值在你离开路由期间发生变化时,返回后并不会重新执行过滤逻辑,导致模型没有更新。
解决方案
下面提供几种可行的解决思路,你可以根据自己的业务场景选择:
方法1:监听currentContract变化,主动刷新路由模型
在路由中监听currentContract服务的属性变化,一旦合约更新就手动触发路由模型的刷新:
// 你的路由文件 import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; import { observer } from '@ember/object'; export default class YourRoute extends Route { @service currentContract; model() { return RSVP.hash({ comptes : this.get('store').findAll('compte'), contrats: this.get('store').findAll('contrat').then(contrats => { return contrats.filterBy("contrat_fk.id", this.currentContract.contrat.id); }), }) } // 监听合约变化,触发模型刷新 @observer('currentContract.contrat') _refreshOnContractChange() { this.refresh(); } // 进入路由时确保监听生效 activate() { this._super(...arguments); this._refreshOnContractChange(); // 可选:首次进入时也触发一次过滤 } }
this.refresh()方法会重新执行model钩子,让路由加载最新的过滤后数据。
方法2:在setupController中动态过滤已有数据
如果不想每次都重新请求后端的contrat数据,可以在路由的setupController钩子中监听合约变化,只在客户端重新过滤已有的数据集合:
// 你的路由文件 import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; import { observer } from '@ember/object'; export default class YourRoute extends Route { @service currentContract; @service store; model() { return RSVP.hash({ comptes : this.store.findAll('compte'), allContrats: this.store.findAll('contrat'), // 先获取全量合约数据 }) } setupController(controller, model) { this._super(...arguments); // 首次加载时过滤数据 this._filterContrats(model.allContrats); // 监听合约变化,实时更新过滤结果 this.addObserver('currentContract.contrat', this, '_filterContrats'); } _filterContrats(allContrats) { const filteredContrats = allContrats.filterBy("contrat_fk.id", this.currentContract.contrat.id); this.controller.set('contrats', filteredContrats); } // 离开路由时移除监听,避免内存泄漏 deactivate() { this._super(...arguments); this.removeObserver('currentContract.contrat', this, '_filterContrats'); } }
这种方式性能更优,因为不需要重复请求后端数据,只是复用已加载的集合进行动态过滤。
方法3:将合约ID作为路由查询参数
如果希望URL能反映当前选中的合约,同时自动触发模型刷新,可以把合约ID设为路由的查询参数:
// 你的路由文件 import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; export default class YourRoute extends Route { @service currentContract; queryParams = { contractId: { refreshModel: true // 当参数变化时,自动重新执行model钩子 } }; model(params) { return RSVP.hash({ comptes : this.get('store').findAll('compte'), contrats: this.get('store').findAll('contrat').then(contrats => { // 优先使用查询参数的ID,没有则用currentContract的当前值 const targetId = params.contractId || this.currentContract.contrat.id; return contrats.filterBy("contrat_fk.id", targetId); }), }) } // 进入路由时同步查询参数为当前合约ID beforeModel() { this._super(...arguments); this.transitionTo({ queryParams: { contractId: this.currentContract.contrat.id } }); } }
这种方式的额外好处是用户可以直接分享带有合约ID的URL,打开后会自动加载对应的数据。
内容的提问来源于stack exchange,提问作者El Poisen
相关产品推荐
相关产品推荐

