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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:29:07