I have a question about dynamic and nested routes in Nuxt.
I will create a kind of calculator. The user can choose a theme and get on the first dynamic routes - called _slug.vue - a dynamic navigation from the API about this theme and inside this navigation the user get the detail information about this theme.
On the _slug.vue page is also a dynamic navigation, from the REST API that trigger on the same page the view like: http://localhost/slug/slug2
first question:
user trigger a theme on startpage, get the navigation on _slug.vue
How can I set the first menu item to active so that its content is displayed directly without the user having to click on the menu item first?
the child-view has to be changed if user click to ther menu items
child view can enter directly on browser and is also available
second question
I need to parse in the second step many params to create all user choices, to share the link to other users.
I will get this by creating vuex store "cart"
how can i implement this with the dynamic routes?
like:
http://localhost/slug/slug2?param1=test¶m2=test2
http://localhost/slug/slug10?param1=test¶m2=test2
You can see that the secondary slug is dynamic, the first slug is only dynamic by choosing this on startpage.
Here is my code:
pages/index.vue
<template>
<nav class="navigation">
<ul>
<li
v-for="(link, index) in links"
:key="index"
>
<nuxt-link
:to="link.shortName"
:data-code="link.shortName"
>
{{ link.name }}
</nuxt-link>
</li>
</ul>
</nav>
</template>
pages/_slug.vue
<template>
<div class="calculator">
<nav class="navigation">
<ul>
<li
v-for="(link, index) in $store.state.calculatorNavigation"
:key="index"
>
<nuxt-link
:to="{ path: '/' + $store.state.carResult.id + '/' + link.id}"
:title="link.name"
append
>
{{ link.shortName }}
</nuxt-link>
</li>
</ul>
</nav>
<nuxt-child></nuxt-child>
</div>
</template>
pages/slug/_category.vue
<template>
<div>
here show the data for every menu point from the first /slug like /slug/slug2
</div>
</template>
Nuxt.js adding special classnames to all nuxt-link instances depending on the current location. By default it sets nuxt-link-active if current location starts with the URL of the nuxt-link and nuxt-link-exact-active if it is exact match (classnames can be adjusted in config).
In Dynamic Pages to get the params of the route you must use asyncData:
<!-- pages/_slug.vue -->
<template>
<h1>{{ this.slug }}</h1>
</template>
<script>
export default {
async asyncData({ params }) {
const slug = params.slug // When calling /abc the slug will be "abc"
return { slug }
}
}
</script>
The same way you could get the query string:
<!-- pages/_slug.vue -->
<template>
<h1>{{ this.slug }} / {{ this.param1 }}</h1>
</template>
<script>
export default {
async asyncData({ params, query }) {
const slug = params.slug
const param1 = query.param1 // When calling /abc?param1=test the param will be "test"
return { slug, param1 }
}
}
</script>
In case you need to access route's params and query on the client-side as well, you can still use $route builtin (ie. for data fetching).
<script>
export default {
mounted() {
const slug = this.$route.params.slug
const param1 = this.$route.query.param1
// some fetching here
}
}
</script>
So, now the structure of your pages should be like this:
pages/
├── _slug/
│ ├── index.vue --> ie. http://localhost/slug/
│ └── _category.vue --> ie. http://localhost/slug/slug2
└── index.vue --> http://localhost/
So, in _slug.vue router parameter slug will be available. And in _category.vue both slug and category params will be available.
Related
I am working on a project that uses Laravel Vue SPA, and I got a problem accessing the data of the single product, it's only working when I click once, but when I select again with other product, I can't get the product data, but the URL is correct it's changes the ID but can't access the data.
It is working when I click another link like Services then select product, it can display the product data.
Here is my HTML
<ul >
<li v-for="product in products">
<router-link :to="{ name: 'edit-product', params: { id: product.id } }">
{{ product.title }}
</router-link>
</li>
</ul>
My Vue Routes
const EditProduct = require('./components/EditProduct').default;
{
path: '/edit/product/:id',
component: EditProduct,
name: 'edit-product'
}
my EditProduct component
<template>
<div>
<h1>this.$route.params.id</h1>
</div>
</template>
Cheers
Look at this answer. You have to watch the productId and execute your logic again.
Possible solution
try to define a computed property inside your EditProduct component for get product id
computed: {
productId(){
return this.$route.params.id
}
}
and use productId inside your <h1> tag
<template>
<div>
<h1>{{ productId }}</h1>
</div>
</template>
update
solution :
add this watcher to your EditProduct component for reacting with params change
watch: {
$route(to) {
console.log(to.params.id)
// you can call your method here and pass product id to them for example: this.getProductDetails(to.params.id)
},
beforeRouteEnter (to, from, next) {
next(vm => {
//also call your method here => vm.getProductDetails(to.params.id)
});
},
you can read more about params changes here: Reacting to Params Changes
Template:
<template>
<nav>
<router-link :to="key" v-for="(value, key) in state.menu" :key="key">{{value}} | </router-link>
</nav>
</template>
Code:
export default {
setup() {
const menu = ['home', 'news', 'about'];
const state = reactive({
menu: {}
});
menu.map(item => {
state.menu[item] = Common.locs[item];
});
return {
Common,
state,
}
}
}
I want to update
:to="key"
to run it through some filter or function to modify it to add the prefix something like "/other/", so instead of rendered
<a href="/home" ...>
I would have
<a href="/other/home" ... >
(Of course, const menu values are mocked for the sake of example; those are fetched from the service so I have no saying in that, and I don't want to modify them after fetching for other reasons)
So in general, my question is not regarding proper routing, but how do you modify v-for data (in my case: key) in the runtime if you need to?
(I guess I could modify mapping line into
state.menu["/other/" + item] = Common.locs[item];
but I want to preserve state.menu as I wrote. I want change to happen during the v-for rendering.)
Have you tried the template literal:
<template>
<nav>
<router-link :to="`/other/${key}`" v-for="(value, key) in state.menu" :key="key">{{value}} | </router-link>
</nav>
</template>
I want to redirect inside a URL without page refresh, without using a router link as below :
<router-link to="/about us " active-class="active">foo</router-link>
I want to print routes like below:
<li class="nav-item phone">
<a class="nav-link" href="contact-us.html">
اتصل بنا
</a>
</li>
My route:
const routes = [
{ path: '/aboutus/', component: AboutUs }
]
Try this
this.$router.push('about')
You may need a workaround for this.
This solution won't change the url either :)
Set an html in the data
data: () => {
return {
html: null
}
}
Get the content of your html file using any request and assign to the html in data section. You can fetch this from any life cycle hook. Here I'm using beforeMount.
beforeMount() {
this.fetchAllEmployees();
axios.get('contact-us.html')
.then(response => {
this.html = response.data;
})
}
Now you can show the html content in your component like this
<template>
<div>
<div v-html="html"></div>
</div>
</template>
To show only when clicking the a tag, you can add another variable in the data which can be used to toggle the value.
I can't seem to find a good way to disable a nuxt-link based on a data variable. Could anyone suggest something? I've tried looking at doucmentation but I can't come up with anything.
Say I have a boolean called disable I want to do something like this
<nuxt-link :disabled="disable"></nuxt-link>
I basically just don't want the link to be clickable if the boolean is set to false
<nuxt-link> is essentially <router-link> of Vue Router.
You can disable it using the event prop.
Assuming your one of your data or computed property is disabled boolean:
<nuxt-link :event="disabled ? '' : 'click'"></nuxt-link>
Working example:
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const Baz = { template: '<div>baz</div>' }
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar },
{ path: '/baz', component: Baz }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router,
data(){
return {
disabled: true
}
}
}).$mount('#app')
<script src="https://unpkg.com/vue#2.7.13/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-router#3.6.5/dist/vue-router.min.js"></script>
<div id="app">
<h1>Hello App!</h1>
<div>
<!-- Assume they are <nuxt-link> because they are the same -->
<router-link
:event="disabled ? '' : 'click'"
to="/foo"
>
Go to Foo ({{ disabled ? 'Disabled' : 'Enabled' }})
</router-link>
<router-link to="/bar">Go to Bar</router-link>
<router-link to="/baz">Go to Baz</router-link>
</div><br />
<button #click="disabled = !disabled">Toggle Foo availability</button><br /><br />
<router-view></router-view>
</div>
I found that the most simple way was to just create a class for the disabled links. I'm still not sure if this is the best way to do it but it works for me and does exactly what I want.
<nuxt-link to="/search" :class="{ disabled: disabled }"> Search </nuxt-link>
my css
.disabled {
color: lightgrey
pointer-events: none
}
Another way to do this, which I'd like the most. Is to change the tag to the button and use the native :disabled state.
<nuxt-link tag="button" :disabled="disabled" to="/some/location">Some location</nuxt-link>
Then just turn the button into the link with the help of styles.
In Nuxt3 this works for me: :to="canNavigate ? link : null"
In Vue Router 4, router-link do not support tag and event props anymore. Here you can have more information.
I'll copy the example from the link above here:
replace
<router-link to="/about" tag="span" event="dblclick">About Us</router-link>
with
<router-link to="/about" custom v-slot="{ navigate }">
<span #click="navigate" #keypress.enter="navigate" role="link">About Us</span>
</router-link>
And I'll give a real example of usage. This piece of code I'm using in a real project, using nuxt and tailwind.
<nuxt-link
v-slot="{ navigate }"
class="flex-grow font-ember"
:to="`lesson/${l.lesson_id}`"
append
custom
>
<button
class="flex items-center"
:class="{
'text-gray-400 cursor-not-allowed': !l.released,
'text-gray-900': l.released,
}"
:disabled="!l.released"
#click="navigate"
>
...
</button>
</nuxt-link>
Just add the event prop if you simply want to disable a nuxt-link
<nuxt-link event="">Go to Foo</nuxt-link>
For this case anyway you can click on it. It displaying disabled but still clickable.
You need to use attribute tag in you nuxt-link
Example here <nuxt-link tag="button" :disabled="disable"></nuxt-link>
None of these seemed to work for me, so I set the :to on the nuxt-link to a computed method. The to attribute on nuxt link will redirect nowhere when empty. For example:
<script>
export default{
computed: {
redirectRequest(){
return this.isMobile ? "" : "/Worklog";
}
}
}
</script>
<template>
<NuxtLink :to="redirectRequest"></NuxtLink>
</template>
I'm struggling to find a way to render the path of the router-link dynamically, for example with the test variable. I'm trying to bind :to but unsuccessfully. I don't know if I can use the ternary operator in the binding as shown below:
<template>
<div>
<router-link
:to="{ test ? '/success' : '/fail' }"
tag="button"
class="btn-next">
<span class="btn-text">BUTTON</span>
</router-link>
</div>
</template>
<script>
export default {
// ...
data: function() {
return {
test: false
};
}
}
</script>
Your solution is close (you don't need the curly brackets). It should look like this:
<router-link :to="test ? '/success' : '/fail'">
demo