Hello. I am implementing a filter table. After writing on the input fields and pressing the button. The value of the title is read and queryParams in the adapter is updated. Can anyone tell me how to update the table when queryParams are defined. This is the action
filterDocuments(param) {
if (param !== '') {
let model=this.modelFor("main.documents.table")
var dcTitle=Ember.get(model,"dcTitle")
this.get('documentsAdapter').filterDocuments(dcTitle, 1, ENV.APP.pageSize)
and my documentsAdapter is like this
export default Service.extend({
ajax: inject('ajax'),
session: inject('session'),
filterDocuments(dcTitle, page, pageSize) {
debugger;
let queryParams = '';
if(!isEmpty(page)){
queryParams+=`page=${page}`
}
else{
queryParams+='page=1'
}
if(!isEmpty(pageSize)){
queryParams+=`&page_size=${pageSize}`
}
else{
queryParams+='&page_size=15'
}
if(!isEmpty(dcTitle)){
queryParams+=`&dc_title=${dcTitle}`
}
return this.get('ajax').request({
url:
`/admins/documents?${queryParams}`,
});
},
I want to know how can I get the url generated by the adapter and then show the table that matches the title entered.
Hi @Abdullah_Ali, seems like you’re doing a lot of unnecessary work here. Building the request URL and such is usually the responsibility of the data layer and Ember Data can handle this automatically. Typically what I would do in a scenario like this is the following:
- Define your query params on your route and probably your controller as well. Something like this:
// your-route.js
export default class YourRoute extends Route {
@service store;
queryParams = {
page: {
refreshModel: true
},
per_page: {
refreshModel: true
},
dc_title: {
refreshModel: true
}
};
model(params) {
return this.store.query('document', params);
}
...
This will set up the route so it queries the backend correctly based on your query params and will refresh the server request query any time your query params change.
- Bind your query params to your route’s controller:
// your-controller.js
...
export default class YourController extends Controller {
queryParams = [{
page: 'page'
}, {
perPage: 'per_page'
}, {
dcTitle: 'dc_title'
}];
page = 1;
pageSize = <default page size>;
dcTitle = null;
}
This binds the (Ember) query params to your controller, so if you set any of the properties on your controller (let’s say you set “perPage” on the controller) it will update the corresponding query param in the page URL and then refresh your route model, which will then send the model changes to the controller and the route template rerendering the table.
That way you don’t need any of the custom adapter code or the more complex action, all you need to do is set any of those properties on the controller and everything else happens for you.
Thanks for the reply @dknutsen, thing is we are not using store in this project instead the adapters are used. And I already defined the queryParams
as you suggested in my route.js
already. As you can see in the screenshot I attached I got the url that is needed
. I just want to pass this url to my route so that the url looks something like this:
example.com/documents?page=1&pageSize=15&dcTitle=towards
and then render the table based on the queryParams.
Ah sorry I wrongfully assumed you were using ember data since you were using “adapter” terminology.
I would put something like this in your router:
model({ dcTitle, page, pageSize }) {
return this.get('documentsAdapter').filterDocuments(dcTitle, page, pageSize);
}
And make sure the query params are bound on your controller. Then anytime you want the route to update you just need to set one or more of those props on the controller. This could be done on button press, on input, etc.
@dknutsen I have an input tag on template that enables an action filterDocuments(param)
that I defined above. My model looks like this:
model(e){
//initializations
return this.get('documents.Adapter')
.queryDocumentsForTable(parameters)//adapter
.then((resp)=>{
return {
//return data
}
})
}
And I used controllers as you suggested. Didn’t work. Ideally I would like route.js
for actions and only use controllers to bind the binding and not use it at all.
The action you defined is fetching the data itself whereas my suggestion was to just have it set one of the controller properties and let the route handle the fetch automatically.
// controller action
filterDocuments(param) {
if (param === '') return;
this.set('dcTitle', param);
}
^ this would simply update the “dcTitle” prop on the controller, which would update the query param, which would cause the route model hook to refire, which would re-render the route template (and therefore your table).
And I used controllers as you suggested. Didn’t work.
What didn’t work? What did you try?
Ideally I would like route.js
for actions and only use controllers to bind the binding and not use it at all.
Why is this ideal? What actions? Putting actions on a route rarely makes sense as it is one step removed from the template context and its main responsibilities can be handled via other mechanisms like query params.
Hi @dknutsen. I meant ideal in sense of keeping the code consistent.
I am now able to filter documents based on the title I enter but there is a small bug in that way. If the search the title name and if they can not be fit in one page and if I try to move to another page the table gets updated and the titles are not filtered.
if the page size is 2 and the values returned are more than that it doesn’t show on the next page.
I used actions to filter the document
export default Route.extend({
queryParams: {
page: {
refreshModel: true,
// set this true because data doesn't update when page is changed
},
pageSize: {
refreshModel: false,
},
dcTitle:{
refreshModel: false,
},
},
async model(e) {
let page = parseInt(e.page) || 1,
pageSize = parseInt(e.pageSize) || ENV.APP.pageSize;
let dcTitle = e.dcTitle;
// CALL ADAPTER TO GET DOCS
return this.get('documentsAdapter')
.queryDocs(page, pageSize)//documents from adapter
.then((resp) => {
return {
results_count: resp.meta.results_count,
document_revisions: resp.document_revisions,
currentPage: page,
numberPerPage: pageSize,
isFiltered: false,
dcTitle: resp.dc_title,
};
});
},
actions: {
filterDocuments() {
//filter the documents upon button click
let model=this.modelFor("main.documents.table")
var dcTitle=Ember.get(model,'dcTitle')
this.get('documentsAdapter').filterDocuments(undefined, undefined, dcTitle,
undefined, undefined, undefined, 1, ENV.APP.pageSize)
.then((resp) => {
Ember.set(model,'document_revisions',resp.document_revisions)
this.controller.setProperties({page: 1,});
});
},
Will really appreciate your help