求助:在Ember中通过查询参数实现JSONAPI过滤器的最优方案
问题:Ember路由中JSONAPI风格的数组类型查询参数无法正确传递
昨天我花了好长时间尝试在Ember应用的查询参数里加入符合JSONAPI规范的filter。用Ember Data给端点传filter数组倒是挺简单,但麻烦的是特定路由的查询参数里没法正确反映这个filter数组——其他非数组类型的查询参数都正常工作,就这个数组型的不行。
TL;DR:试了好几种方法都没搞定,现有的解决方案不够DRY(Don't Repeat Yourself),用起来体验太差。我觉得肯定有其他开发者已经解决过这个问题,找到了更优雅的方案,下面是我目前的尝试细节:
最初的尝试(参考Ember官方文档)
我照着Ember查询参数的官方文档写了下面的代码:
Controller代码
import Controller from '@ember/controller'; export default Controller.extend({ queryParams: ['sort', 'filter'], sort: 'id', init() { this._super(...arguments); this.set('filter', []); }, });
Route代码
import Route from '@ember/routing/route'; export default Route.extend({ queryParams: { filter: { refreshModel: true }, sort: { refreshModel: true } }, model(params) { console.log(JSON.stringify(params)); // filter始终是[] return this.get('store').query('contact', params); } });
验收测试代码
(这是用来验证概念的测试,之后会扩展更复杂的逻辑)
test('visiting /contacts with query params', async function(assert) { assert.expect(1); let done = assert.async(); server.createList('contact', 10); server.get('/contacts', (schema, request) => { let params = request.queryParams; assert.deepEqual( params, { sort: '-id', "filter[firstname]": 'wibble' }, 'Query parameters are passed in as expected' ); done(); return schema.contacts.all(); }); await visit('/contacts?filter[firstname]=wibble&sort=-id'); });
不管我怎么调整上面的代码,Route的model函数里params.filter始终是空数组[]。
找到的旧方案(但不够理想)
我搜了这个场景的最佳实践,但没找到近期的资料。有个2015年的方案是可行的,但需要在Controller和Route里硬编码所有可能的filter键——这太不友好了,试想如果要处理20个以上的filter键会有多麻烦!
下面是用这个方案实现上述验收测试的代码:
Controller代码
import Controller from '@ember/controller'; export default Controller.extend({ queryParams: ['sort', { firstnameFilter: 'filter[firstname]' } ], sort: 'id', firstnameFilter: null, init() { this._super(...arguments); } });
Route代码
import Route from '@ember/routing/route'; export default Route.extend({ queryParams: { firstnameFilter: { refreshModel: true }, sort: { refreshModel: true } }, model(params) { if (params.firstnameFilter) { params.filter = {}; params.filter['firstname'] = params.firstnameFilter; delete params.firstnameFilter; } return this.get('store').query('contact', params); } });
我真的希望能找到一个更优的解决方案!
内容的提问来源于stack exchange,提问作者casafred
相关产品推荐
相关产品推荐

