Related
I configured routing module as following:
const routes: Routes = [
{
path: "engineering/:branches",
component: BranchesTabsComponent
},
{
path: "humanities/:branches",
component: BranchesTabsComponent
},
];
and in the main-continer.component.ts:
titlesOfEngineeringTabs: string[] = ['E1','E2','E3'];
titlesOfHumanitiesTabs: string[] = ['H1','H2'];
constructor(private router: Router) {}
handleEnginTabs():void{
this.router.navigate(['/engineering', this.titlesOfEngineeringTabs]);
}
handleHumanTabs():void{
this.router.navigate(['/humanities', this.titlesOfHumanitiesTabs]);
}
and also main-continer.component.html contains:
<router-outlet></router-outlet>
and then in branches-tabs.component.ts have:
tabsLable: string[] = [''];
ngOnInit(): void {
this.route.params.subscribe(param => this.tabsLable = param["branches"]);
}
till here, it is obvious that we want to replace <router-outlet> with branches-tabs component in which deferent tab labels are shown Depending on selected menu...
but I get this error:
*core.mjs:6485 ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'engineering;0=%DA%A9%D8%A7%D9%85%D9%BE%DB%8C%D9%88%D8%AA%D8%B1;1=%D8%B5%D9%86%D8%A7%DB%8C%D8%B9;2=%D9%85%D8%AA%D8%A7%D9%84%D9%88%D8%B1%DA%98%DB%8C'
Error: Cannot match any routes. URL Segment: 'engineering;0=%DA%A9%D8%A7%D9%85%D9%BE%DB%8C%D9%88%D8%AA%D8%B1;1=%D8%B5%D9%86%D8%A7%DB%8C%D8%B9;2=%D9%85%D8%AA%D8%A7%D9%84%D9%88%D8%B1%DA%98%DB%8C'*
how can pass a string array as parameter and fix above error?
best regards
Angular docs on navigate()
An array of URL fragments with which to construct the target URL. If
the path is static, can be the literal URL string. For a dynamic
path, pass an array of path segments, followed by the parameters for
each segment. The fragments are applied to the current URL or the
one provided in the relativeTo property of the options object, if
supplied.
If your intent is to have the url look like /engineering/E1/E2/E3 then you should apply the spread operator ... to the arrays and it would look like:
this.router.navigate(['/engineering', ...this.titlesOfEngineeringTabs]);
If you want to put the array in the url, it needs to be a string. So you can use JSON.stringify() and JSON.parse()
handleEnginTabs():void{
this.router.navigate(['/engineering', JSON.stringify(this.titlesOfEngineeringTabs)]);
}
ngOnInit(): void {
this.route.params.subscribe(param => this.tabsLable = JSON.parse(param["branches"]));
}
But queryParams is probably more appropriate.
handleEnginTabs(): void {
this.router.navigate(['/engineering'], {
queryParams: { branches: this.titlesOfEngineeringTabs },
});
}
ngOnInit(): void {
this.tabsLable = this.route.snapshot.queryParams['branches'];
}
and removing the parameter from the path
{
path: "engineering",
component: BranchesTabsComponent
},
Keep in mind the user can change the values of your array by editing the url. If that's something you don't want to happen, you'll have to use other means of passing the data.
This thread goes over some other ways of passing data to routes:
How do I pass data to Angular routed components?
However, a lot of them will not persist on refresh. So if you want that, you'll have to write to / read from localStorage as well.
In a javacscript file I have something that looks like this,
module.exports = {
ROUTES: [
{"route1" : "route-1"},
{"route2" : "route-2"},
{"route3" : "route-3"}
]
}
I am doing the following to use these values in another file,
const routes = require("/routes");
meaning to access the values I have to do the following,
routes.ROUTES.route1
Is it possible to import the ROUTES array directly from the file so I can do,
ROUTES.route1
Since you're using common JS modules, you can use destructuring:
const { ROUTES } = require('./routes');
You could also export the routes array directly if you don't have anything else in the file:
module.exports = [
{"route1" : "route-1"},
{"route2" : "route-2"},
{"route3" : "route-3"}
]
That way you could keep your import:
const routes = require("/routes");
I am trying to add dynamic routes to my vue router (using router.addRoute()). It works so far, but I get a problem as soon as I try to set a component for my dynamic route.
This is the code that works:
var name = "reports";
var path = "reports/foo";
var item = {
name: name,
path: path,
component: () => import( "../pages/reports/Reports_Foo.vue" )
};
When calling the page it correctly loads the content of my Reports_Foo.vue
But when I want to load the vue file dynamically, like this:
var filename = "Reports_Foo";
var name = "reports";
var path = "reports/foo";
var item = {
name: name,
path: path,
component: () => import( "../pages/reports/"+filename+".vue" )
};
It no longer works and I get the following javascript error:
TypeError: Failed to fetch dynamically imported module: https://localhost:123456/js/pages/reports/Reports_Foo.vue
Why? Do you know a way to fix this ?
Edit: I'm using rollup to convert the files into chunks and then reference them.
Try explicitly loading the default export:
var item = {
name: name,
path: path,
component: async () => (await import("../pages/reports/"+filename+".vue")).default
}
In my NextJS app, I have a language selector that's visible on every page. When I select a new language, I just want to replace the current URL by appending a query param lang=en to it.
Here's the function that replaces the URL:
const changeLanguage = (lang: LanguageID) => {
replace({
pathname,
query: { ...query, lang },
});
};
In this example, replace, query and pathname are coming from the next router.
Now, everything works for static routes, but I'm unable to make it work for dynamic routes. For example, I have the following folder structure:
pages
|_customers
|__index.tsx
|__[customerId].tsx
If I'm on http://localhost/customers and I change my language to English, the URL changes to http://localhost/customers?lang=en which is what I want. However, if I'm on http://localhost/customer/1 and I change my language to English, the URL changes to http://localhost/customers/[customerId]?customerId=1&lang=en, instead of the URL I'm expecting http://localhost/customers/1?lang=en.
Now, I know that I could use asPath on the router, and reconstruct the query string object by appending lang to it, but I feel that it's something that should be build into Next. Also, I know it could be easily done with vanilla JS, but it's not the point here.
Am I missing something? Is there an easier way to append query params to a dynamic route without doing a server-side re-rendering?
Thanks
Just add more param to current router then push itself
const router = useRouter();
router.query.NEWPARAMS = "VALUE"
router.push(router)
The solution which doesn't need to send the whole previous route, as replace just replaces what we need to replace, so query params:
const router = useRouter();
router.replace({
query: { ...router.query, key: value },
});
If we want to have this as a link - use it like so:
// ...
const { query } = useRouter();
// ...
<Link
href={{
pathname: router.pathname,
query: { ...query, lang },
}}
passHref
shallow
replace
></Link>
I tried adding my param to the route query and pushing the router itself, as mentioned here, it works, but I got a lot of warnings:
So, I then pushed to / and passed my query params as following:
const router = useRouter();
router.push({ href: '/', query: { myQueryParam: value } });
I hope that works for you too.
I ended up using the solution that I wanted to avoid in the first place, which was to play with the asPath value. Atleast, there's no server-side re-rendering being done since the path is the same.
Here's my updated changeLanguage function (stringifyUrl is coming from the query-string package)
const changeLanguage = (lang: LanguageID) => {
const newPathname = stringifyUrl({ url: pathname, query: { ...query, lang } });
const newAsPath = stringifyUrl({ url: asPath, query: { lang } });
replace(newPathname, newAsPath);
};
If anyone is still looking the answer ,for Next,js ^11.1.2.I hope this helps you out.Use
const router = useRouter();
router.push({ pathname: "/search", query: { key: key } });
An alternative approach when you have dynamic routing in Next.js, and want to do a shallow adjustment of the route to reflect updated query params, is to try:
const router = useRouter()
const url = {
pathname: router.pathname,
query: { ...router.query, page: 2 }
}
router.push(url, undefined, { shallow: true })
This will retreive the current path (router.pathname) and query (router.query) details, and merge them in along with your new page query param. If your forget to merge in the existing query params you might see an error like:
The provided href value is missing query values to be interpolated
properly
In latest version, Next 13, some of the functionality moved to other hooks, which query and path are some of them. You can use useSearchParams to get query and usePathname instead of pathname. By the time I am writing this answer, it does not have a stable version and you can find the beta documents here:
https://beta.nextjs.org/docs/api-reference/use-router
let queryParams;
if (typeof window !== "undefined") {
// The search property returns the querystring part of a URL, including the question mark (?).
queryParams = new URLSearchParams(window.location.search);
// quaeryParams object has nice methods
// console.log("window.location.search", queryParams);
// console.log("query get", queryParams.get("location"));
}
inside changeLanguage,
const changeLanguage = (lang: LanguageID) => {
if (queryParams.has("lang")) {
queryParams.set("lang", lang);
} else {
// otherwise append
queryParams.append("lang", lang);
}
router.replace({
search: queryParams.toString(),
});
};
I am trying to set query params with Vue-router when changing input fields, I don't want to navigate to some other page but just want to modify url query params on the same page, I am doing like this:
this.$router.replace({ query: { q1: "q1" } })
But this also refreshes the page and sets the y position to 0, ie scrolls to the top of the page. Is this the correct way to set the URL query params or is there a better way to do it.
Edited:
Here is my router code:
export default new Router({
mode: 'history',
scrollBehavior: (to, from, savedPosition) => {
if (to.hash) {
return {selector: to.hash}
} else {
return {x: 0, y: 0}
}
},
routes: [
.......
{ path: '/user/:id', component: UserView },
]
})
Here is the example in docs:
// with query, resulting in /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
Ref: https://router.vuejs.org/en/essentials/navigation.html
As mentioned in those docs, router.replace works like router.push
So, you seem to have it right in your sample code in question. But I think you may need to include either name or path parameter also, so that the router has some route to navigate to. Without a name or path, it does not look very meaningful.
This is my current understanding now:
query is optional for router - some additional info for the component to construct the view
name or path is mandatory - it decides what component to show in your <router-view>.
That might be the missing thing in your sample code.
EDIT: Additional details after comments
Have you tried using named routes in this case? You have dynamic routes, and it is easier to provide params and query separately:
routes: [
{ name: 'user-view', path: '/user/:id', component: UserView },
// other routes
]
and then in your methods:
this.$router.replace({ name: "user-view", params: {id:"123"}, query: {q1: "q1"} })
Technically there is no difference between the above and this.$router.replace({path: "/user/123", query:{q1: "q1"}}), but it is easier to supply dynamic params on named routes than composing the route string. But in either cases, query params should be taken into account. In either case, I couldn't find anything wrong with the way query params are handled.
After you are inside the route, you can fetch your dynamic params as this.$route.params.id and your query params as this.$route.query.q1.
Without reloading the page or refreshing the dom, history.pushState can do the job.
Add this method in your component or elsewhere to do that:
addParamsToLocation(params) {
history.pushState(
{},
null,
this.$route.path +
'?' +
Object.keys(params)
.map(key => {
return (
encodeURIComponent(key) + '=' + encodeURIComponent(params[key])
)
})
.join('&')
)
}
So anywhere in your component, call addParamsToLocation({foo: 'bar'}) to push the current location with query params in the window.history stack.
To add query params to current location without pushing a new history entry, use history.replaceState instead.
Tested with Vue 2.6.10 and Nuxt 2.8.1.
Be careful with this method!
Vue Router don't know that url has changed, so it doesn't reflect url after pushState.
Actually you can push query like this: this.$router.push({query: {plan: 'private'}})
Based on: https://github.com/vuejs/vue-router/issues/1631
Okay so i've been trying to add a param to my existing url wich already have params for a week now lol,
original url: http://localhost:3000/somelink?param1=test1
i've been trying with:
this.$router.push({path: this.$route.path, query: {param2: test2} });
this code would juste remove param1 and becomes
http://localhost:3000/somelink?param2=test2
to solve this issue i used fullPath
this.$router.push({path: this.$route.fullPath, query: {param2: test2} });
now i successfully added params over old params nd the result is
http://localhost:3000/somelink?param1=test1¶m2=test2
If you are trying to keep some parameters, while changing others, be sure to copy the state of the vue router query and not reuse it.
This works, since you are making an unreferenced copy:
const query = Object.assign({}, this.$route.query);
query.page = page;
query.limit = rowsPerPage;
await this.$router.push({ query });
while below will lead to Vue Router thinking you are reusing the same query and lead to the NavigationDuplicated error:
const query = this.$route.query;
query.page = page;
query.limit = rowsPerPage;
await this.$router.push({ query });
Of course, you could decompose the query object, such as follows, but you'll need to be aware of all the query parameters to your page, otherwise you risk losing them in the resultant navigation.
const { page, limit, ...otherParams } = this.$route.query;
await this.$router.push(Object.assign({
page: page,
limit: rowsPerPage
}, otherParams));
);
Note, while the above example is for push(), this works with replace() too.
Tested with vue-router 3.1.6.
Here's my simple solution to update the query params in the URL without refreshing the page. Make sure it works for your use case.
const query = { ...this.$route.query, someParam: 'some-value' };
this.$router.replace({ query });
My solution, no refreshing the page and no error Avoided redundant navigation to current location
this.$router.replace(
{
query: Object.assign({ ...this.$route.query }, { newParam: 'value' }),
},
() => {}
)
this.$router.push({ query: Object.assign(this.$route.query, { new: 'param' }) })
You could also just use the browser window.history.replaceState API. It doesn't remount any components and doesn't cause redundant navigation.
window.history.replaceState(null, '', '?query=myquery');
More info here.
For adding multiple query params, this is what worked for me (from here https://forum.vuejs.org/t/vue-router-programmatically-append-to-querystring/3655/5).
an answer above was close … though with Object.assign it will mutate this.$route.query which is not what you want to do … make sure the first argument is {} when doing Object.assign
this.$router.push({ query: Object.assign({}, this.$route.query, { newKey: 'newValue' }) });
To set/remove multiple query params at once I've ended up with the methods below as part of my global mixins (this points to vue component):
setQuery(query){
let obj = Object.assign({}, this.$route.query);
Object.keys(query).forEach(key => {
let value = query[key];
if(value){
obj[key] = value
} else {
delete obj[key]
}
})
this.$router.replace({
...this.$router.currentRoute,
query: obj
})
},
removeQuery(queryNameArray){
let obj = {}
queryNameArray.forEach(key => {
obj[key] = null
})
this.setQuery(obj)
},
I normally use the history object for this. It also does not reload the page.
Example:
history.pushState({}, '',
`/pagepath/path?query=${this.myQueryParam}`);
The vue router keeps reloading the page on update, the best solution is
const url = new URL(window.location);
url.searchParams.set('q', 'q');
window.history.pushState({}, '', url);
With RouterLink
//With RouterLink
<router-link
:to="{name:"router-name", prams:{paramName: paramValue}}"
>
Route Text
</router-link>
//With Methods
methods(){
this.$router.push({name:'route-name', params:{paramName: paramValue}})
}
With Methods
methods(){
this.$router.push({name:'route-name', params:{paramName, paramValue}})
}
This is the equivalent using the Composition API
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
router.push({ path: 'register', query: { plan: 'private' }})
</script>
You can also use the Vue devtools just to be sure that it's working as expected (by inspecting the given route you're on) as shown here: https://stackoverflow.com/a/74136917/8816585
Update
That will meanwhile mount/unmount components. Some vanilla JS solution is still the best way to go for that purpose.