I have a product page with path product/[id]/index.js. I would like to 'prettify' the product url for SEO purposes. I would like the url to look like product/usb-mouse-black instead of product/121122-001 I need to pass the query ID to populate the product details.
slug=usb-mouse-black
<Link as={`/reservas/${slug}`} href={{pathname: `/product/[id]`, query: {id: idkey}}}>
<Button disableElevation size="small" className={classes.button} variant="contained" color="primary" onClick={(event) => { return true }}>Solicitar Disponibilidax</Button>
</Link>
ID=121122-001
Then I try to get the ID :
const { id } = router.query
Currently getting usb-mouse-black as ID instead of 121122-001
It is better to parse the product name on product/[id]/index.js rather than specifying in the Link tag. It will improve the SSO effect in Google and other search engines.
const { slug } = router.query
const id = parseSlugToId(slug);
If you still prefer your way, try this:
<Link as={`/product/${slug}`} href={`/product/${idkey}`}>{ /* your code goes here */</Link>
I just use the Link in it's most simplified form:
<Link href={`/product/${idkey}`}>
<Button disableElevation size="small" className={classes.button} variant="contained" color="primary" onClick={(event) => { return true }}>Solicitar Disponibilidax</Button>
</Link>
Remember that /reservas/[id]/index.js is the same as /reservas/[id].js no further configuration is necessary
Related
I am using VueJS 3 and want to validate my step by step screen with single OR multiple input fields and want to check is he field valid or not and based on that I have to enable next button.
For validation I am using vee-validate plugin 4.7.3.
In my case I also do not want to use the form tag if possible. As my field is independent so no need to use form.
But as I search and read the comments of the package owner and mentioned that need to use Form so I used it but I just want to check the field validation as I have to show/hide the next button.
Component.vue
<template>
<Form :validateOnModelUpdate="true">
<Field name="mobile" as="input" :rules="mobileRules" v-model="mobile" />
</Form>
// Want to display button if the validation match
// Out side of the form
<button class="btn btn-default" v-if="IF_VALID" > Next </button>
</template>
<script>
import * as Yup from 'yup';
export default {
data(){
return {
mobile: '',
mobileRules: Yup.string().required().min(6)
}
}
}
</script>
If is there anyway to access the meta of the Field then may be that will be helped me.
Thanks.
I have tried to user UseField/useIsFieldValid but it shows me error that the
field with name mobile was not found
Also tried to use ref on the field but I can't able to access the meta of the Field
I have fixed it by using following code change:
For the field level validation need to code like this.
You can access field meta data in your component anywhere out of the Form
As per the owner comment if need to access this type of data out of the component need to achieve like this.
Owner Comment on Discussion
<template>
<div>
<form > <!-- This is simple HTML form -->
<input class="form-control" type="text" name="mobile" v-model="mobile" placeholder="000-0000-000">
<span class="text-danger" v-if="mobileErr">{{ mobileErr }}</span>
</form>
<button v-if="mobileMeta.valid"> Next </button>
</div>
</template>
<script>
import * as Yup from 'yup';
import { useField } from 'vee-validate';
export default {
setup(){
const mobileRules = Yup.string().required('Required').min(10, 'Must be 10 digits');
const { meta: mobileMeta, value: mobile, errorMessage: mobileErr} = useField('mobile', mobileRules);
return {
mobileMeta,
mobile,
mobileErr
}
},
data(){
return {
steps: '',
loading: false
}
},
created(){
},
methods:{
methodOne () {
// Some code to perform
},
methodTwo () {
// Some code to perform
}
}
}
</script>
Hopefully it will helps to others who want to perform step by step form and need to valid the field one by one.
Thanks.
I have a page where I fetch data and map through it.
In my map function I display a card component with some data like this:
pokemonsList?.map((pokemon, index) => {
return (
<Link href={`/pokemon/${pokemon.id}`} key={index}>
<a>
<Card pokemon={pokemon} />
</a>
</Link>
);
}
As you can see, the route is dynamic.
What I would like to do is to pass the whole pokemon object to the page.
I would like to achieve this without using the next router query method, because the object contains a lot of data.
Is there an other way ?
You could cache it, either by using some global state management package (Redux, React Query) or inbuilt Context API.
Or
<Link
href={{
pathname: '/pokemon',
query: {
id: pokemon.id,
pokemon: JSON.stringify(pokemon)
}
}}
as={`/pokemon/${pokemon.id}`}
key={index}>
<a>
<Card pokemon={pokemon} />
</a>
</Link>
And then on the page
const { query } = useRouter();
const pokemon = JSON.parse(query.pokemon);
I am new to Nextjs and Stackoverflow so I will try to describe my issue as best as possible.
I have created the following folder structure in my project:
pages
api folder
index.js
sys-admin folder
createvenue.js
createuser.js
index.js
Inside sys-admin>index.js, I have a button with an onClick handler that uses next/router to push to the createvenue.js route. When I type in the URL http://localhost:3000/sys-admin/createvenue, I can see the createvenue.js page however, when I click the button in the http://localhost:3000/sys-admin page, I am directed to http://localhost:3000/createvenue which gives me a 404. My understanding was that the folder name (in this case sys-admin) would become the root and would be added to the router path to make the URL http://localhost:3000/sys-admin/createvenue.
Here is my sys-admin>index.js code:
import { useRouter } from "next/router";
export default function CreateCustomer() {
const router = useRouter();
const handleSubmit = () => {
router.push("/createvenue");
};
return (
<>
<form onSubmit={handleSubmit}>
<button className="btn btn-filled">Create New Customer</button>
</form>
</>
);
}
Here is my createvenue.js code:
import { useRouter } from "next/router";
export default function CreateVenue() {
const router = useRouter();
const handleSubmit = () => {
router.push("/createusers");
};
return (
<>
<form onSubmit={handleSubmit}>
<input type="text" placeholder="Enter venue name" />
<button className="btn btn-filled">Next</button>
</form>
</>
);
}
I've also tried adding /sys-admin to router.push("/sys-admin/createvenue"); but it still doesn't work.
Is there a way to get next/router to add the sys-admin root to the URL?
The default Behaviour of the form is to refresh the Page once it submitted. You have to prevent the form event from refreshing the page.
export default function CreateVenue() {
const router = useRouter();
const handleSubmit = (event) => {
// preventing the form event from refreshing the page
event.preventDefault()
router.push("/createusers");
};
return (
<>
<form onSubmit={(e)=>handleSubmit(e)}>
<input type="text" placeholder="Enter venue name" />
<button className="btn btn-filled">Next</button>
</form>
</>
);
}
Accessibility best practices suggest using <button> for button elements.
Prefetching for Next.js can be done via <Link>.
However, when you combine the two and use the Tab key to navigate, it will essentially select that button twice. E.g.
<Link href="#">
<a>
This selects once
</a>
</Link>
<Link href="#">
<a>
<button>
This selects twice
</button>
</a>
</Link>
You could do something like this:
<button
onClick={() => { window.location.href "#" }
>
This only selects once
</button>
But that doesn't prefetch.
You can use router.prefetch to fetch the route before going to the page. Check this for more details
export default function Login() {
const router = useRouter()
const onClick = useCallback((e) => {
router.push('/dashboard')
}, []);
useEffect(() => {
router.prefetch("/dashboard"); // Prefetch the dashboard page
}, [])
return (
<button onClick={onClick}>Login</button>
)
}
this is for nuxt
you don't need to do that way, you can just add props and value into nuxtlink
<NuxtLink
id="home-link"
:to="localePath('/')"
exact
active-class="nav-active"
tag="button"
class="btn btn-primary"
>
Home/Any Name
</NuxtLink>
for next top answer is right
export default function Login() {
const router = useRouter()
const onClick = useCallback((e) => {
router.push('/dashboard')
}, []);
useEffect(() => {
router.prefetch("/dashboard"); // Prefetch the dashboard page
}, [])
return (
<button onClick={onClick}>Login</button>
)
}
From my understanding NEXT should be automatically generating the routes based on my folder structure.
I am mapping over article posts on news/index.tsx page but the urls I get are localhost3000/article-one when I need localhost3000/news/article-one
Can anyone point out where I'm going wrong?
{page?.articles.map((post, i) => {
return (
<Link
key={i}
href={post?.slug.current!}
>
{post?.title!}
</Link>
)
})}
Folder structure:
- pages
- news
- index.tsx
- [slug].tsx
EDIT
Addiction info:
Slugs are being pulled from Sanity headless CMS.
Tutorials often show routing by prepending news/ to the slug but this in turn is prepending news/ to all slugs
You can handle the dynamic routes in Next js in few ways, one of those is with With URL Object:
{page?.articles.map((post, i) => {
return (
<Link
key={i}
href={{
pathname: '/news/[slug]',
query: { slug: post?.slug?.current },
}}
>
<a>
{post?.title!}
</a>
</Link>
)
})}
Additional disclaimer. You always must add the anchor <a>...</a> as a child of Link Component.
Documentation: https://nextjs.org/docs/api-reference/next/link#with-url-object
Turns out to be a really simple fix..
The nav links that were getting /news/news prepended to their slugs needed a / prepended before them
From what I understand you should change your code to have the correct href:
{page?.articles.map((post, i) => {
return (
<Link
key={i}
href={`/news${post?.slug.current!}`}
>
{post?.title!}
</Link>
)
})}