Reputation: 352
I have a search form with several filters. They are distributed in text inputs, checkboxes e radios buttons. Every interaration with those filters must update the query string of the URL.
I can also have the following case:
http://example.com/search?myFilter=1&myFilter=2&myFilter=3
Which will be translated to an array like this: myFilter = ['1', '2', '3'].
The code to update the query string is as follows:
this.router.navigate([], {queryParams: myNewQueryString, relativeTo: this.routerActive});
Where "this.router" is an instance of ActivatedRoute and "myNewQueryString" is the object containing the new parameters of the query string. What this code do is to redirect the route to itself updating the query string.
Before updating the query string with new filters, I need to make sure that I will not loose the others filters that are already part of the URL. So what I need to do is to read the query string, make the changes I need and then return the values to the URL.
To read the query string I use this code:
const currentQueryString: any = this.routerActive.snapshot.queryParams;
From that I could start make the changes I require and move on, but the problem is that by attempting to change the properties of this object, Angular gives me the following error:
TypeError: Cannot assign to read only property 'parameter' of object
This errors happens because the properties of:
this.routerActive.snapshot.queryParams
Are all read-only, so I can not make modifications direct to them. What I need to do is to copy the properties to a new object, like this:
const newQueryString: any = {};
for (const key in currentQueryString) {
if (currentQueryString.hasOwnProperty(key)) {
newQueryString[key] = currentQueryString[key];
}
}
Now I have a copy of the current query string which I can make modifications to it. The problem is that when I have multiple values in an Array, the query string does not get updated. It updates only for the first value.
Is this a bug? Is there a better approach to this?
The full code I'm working on is this:
//query is an object like: { 'param' : 'value' }
updateQueryString(query: any): void {
const currentQueryString: any = this.routerActive.snapshot.queryParams;
const newQueryString: any = {};
//Copy the current query string
for (const key in currentQueryString) {
if (currentQueryString.hasOwnProperty(key)) {
newQueryString[key] = currentQueryString[key];
}
}
// Apply the new filter to the copy of the query string
for (const key in query) {
if (query.hasOwnProperty(key)) {
if (newQueryString[key] instanceof Array) {
newQueryString[key].push(query[key]);
} else {
const filter = [];
filter.push(query[key]);
newQueryString[key] = filter;
}
}
}
this.router.navigate([], {queryParams: newQueryString, relativeTo: this.routerActive});
this.search(newQueryString);
}
There are other validations that I need to do in this function, but right now I only want to make the changes to the URL. I'm treating every parameter as an Array, because I can have that scenario I mentioned on the beginning of this question.
Upvotes: 1
Views: 1134
Reputation: 352
It seems the problem was in the process of copying from the current query string to the new one. For some reason we need to provide a new instance of the array so Angular can understand the change and apply it to the URL.
To provide this new instance, we can change:
This:
newQueryString[key] = currentQueryString[key];
Into this:
newQueryString[key] = Array.from(currentQueryString[key]);
By creating a new instance of the array the problem was solved and the changes I needed are now reflected on the URL.
There are several others validations required to make this read-copy-change-apply query string proccess ok, but I don't think those details are quite relevant once the problem was in how to deal with the instances provided by the ActivatedRoute.
If someone stumbles on some problem like this, apparently just work with new instances of the objects and you're good to go.
Upvotes: 1