How to interpolate nuxt-link's `to` prop? - vue.js

I've been searching this for a while but can't seem to get it right. I have a basic Nuxt project with the following directory structure (ignore the fun.vue) :
The idea is to be able to navigate to a single post with paths like http://localhost:3000/posts/1
This works, if I manually go to .../posts/1 I get my page defined in _id.vue.
The problem is that, in my index page, I cannot get <NuxtLink> to go to single post pages. I have a basic v-for looping over my fetched posts array, like so:
<template>
<div>
<div v-for="post in posts" :key="post.id">
{{ post.title }}
<NuxtLink to="`posts/${post.id}`">Link to post</NuxtLink>
</div>
</div>
</template>
I would expect, upon clicking on the 2nd post's link for example, to navigate to posts/2, but instead I get /%60posts/$%7Bpost.id%7D%60. Why isn't the template string converted normally? I've also tried using a computed value with no success, and the Nuxt Routing docs haven't been of much help.
Highly appreciate any help regarding this.

You forgot the semicolon:
:to="`/posts/${post.id}`"
or even better
:to="{ name: 'post-id' }" // post-id or basically the name you gave to your component
As shown here: https://router.vuejs.org/api/#router-link-props

You can use something like this
the ":" in front of it will make it dynamic and you can use template literals
in between those double quotes
<NuxtLink :to="`posts/${post.id}`">Link to post</NuxtLink>

I tried your code in my development environment. You also may forgot to add "/" in front of "posts":
<NuxtLink :to="`/posts/${post.id}`">Link to post</NuxtLink>
If you put your code without "/" in a Nuxt "layout", it adds "posts" iteratively to your "URL" and makes the destination wrong:
http://localhost:3000/posts/posts/2
This happens when you click on post 1 and after to post 2.

Related

How to set src of image dynamically from local json in vue js3

My App.vue has a V-for to create a Card Component, this Card receives the data through a Prop. Everything works fine except for the image.
In my App.vue
<DevJobCard :Job="item" v-for="item in filterSearch" v-bind:key="item.id"/>
The urls that my json provides
"logo": "./assets/logos/scoot.svg",
At the moment the only solution I have found is to put the images in the static folder and use this code so that you can at least see it in production. Help me please :( I haven't made any progress in 2 days
<img v-on="check" :src="'/static' + Job.logo.substring(1)" alt="">
I would like to know how to make it work if they are in assets or in static
If you want to load them by webpack you can simply use :src="require('path/to/file')". Try this code:
<img v-on="check" :src="require('/static' + Job.logo.substring(1))" alt="">
Your project is built, and image paths in the build can change after the build process.
You can try using the require() function. It works at build time:
// v-for="item in yourObject"
<img :src="require('./assets/logos/' + item.logo)" />
This way, webpack will know it needs to change the path to post-build one.
You may want to check this question out: https://stackoverflow.com/a/57350255/1722529

Vue 3 / Vue Router 4 router-link won't use full link from prop

I have a prop that's supposed to pass "careers/whatever-entry-here", and I'm trying to use router-link to set it up.
<router-link v-if="!buttonLink" :to="buttonEntry" exact class="bunch-of-classes-here">
Click Here
</router-link>
I am expecting the link to render as "http://localhost:3000/careers/whatever-entry-here" - but instead I get "http://localhost:3000/whatever-entry-here".
I have looked everywhere but I can't seem to get it to pass the folder to the URI.
When I output {{ buttonEntry }} somewhere else in the template, it outputs it "careers/whatever-entry-here"
Any suggestions?
Ahh. Requires a '/' before the URI, which the API wasn't returning.
Solved by changing the code to:
<router-link v-if="!buttonLink" :to="`/`+buttonEntry" exact class="bunch-of-classes-here">
Click Here
</router-link>

How to use `v-if` and `v-for` on the same element?

Hi I'm trying to figure out how to use v-if on a iterated element which also uses v-for. I need to check if the current element has any of a series of classes, which are numbers.
so the classes of each article would be:
<article class="post-item post-guide 12 22 19 30 55">...
this is the HTML that renders all:
<article v-if="showIfHasClass" :class="'post-item post-guide ' + guide.categories.toString().replace(/,/g, ' ')"
v-for="(guide, index) in guides" :key="index">
<header>
<h1 class="post-title">
{{ guide.title.rendered}}
</h1>
</header>
</article>
I have tried with methods that check the class of all elements, that works, but i'm trying to use a clean Vue built-in solution with v-if without success, i'm not able to retrieve the class of this in a successful way.
Should showIfHasClass be a computed property? I have tried with that too... but it seems, I'm missing something along the way.
my data I have to check against is an array:
data:{
guides: [...]
selectedCategories: [1, 22, 33, 100, 30];
}
or maybe it is better to directly loop over the guides and check if they have the selectedCategory or not, then remove the element from the guides data array?
What is more effective?
Besides the option to create an additional filtered computed (effectively eliminating the need to use v-for and v-if on the same element), you also have a template level way of dealing with such edge-cases: the <template> tag.
The <template> tag allows you to use arbitrary template logic without actually rendering an extra element. Just remember that, because it doesn't render any element, you have to place the keys from the v-for on the actual elements, like this:
<template v-for="(guide, index) in guides">
<article v-if="isGuideVisible(guide)"
:key="index"
class="post-item post-guide"
:class="[guide.categories.toString().replace(/,/g, ' ')]">
<header>
<h1 v-text="guide.title.rendered" />
</header>
</article>
</template>
isGuideVisible should be a method returning whether the item is rendered, so you don't have to write that logic inside your markup. One advantage of this method is that you can follow your v-if element with a fallback v-else element, should you want to replace the missing items with fallback content. Just remember to also :key="index" the fallback element as well.
Apart from the above use-case, <template> tags come in handy when rendering additional wrapper elements is not an option (would result in invalid HTML markup) (i.e: table > tr > td relations or ol/ul > li relations).
It's mentioned here as "invisible wrapper", but it doesn't have a dedicated section in the docs.
Side note: since you haven't actually shown what's inside guide.categories, I can't advise on it, but there's probably a cleaner way to deal with it than .toString().replace(). If guide.categories is an array of strings, you could simply go: :class="guide.categories".
I think the most Vue way is to create a computed property with filtered items from selected categories, then use that in v-for loop (the idea is to move the business logic away from template).
computed: {
filteredItems(){
return this.guides.filter(e => this.selectedCategories.includes(e.category))
}
}
Also, as a note, it is not recommended to use v-if and v-for on the same element, as it may interfere with the rendering and ordering of loop elements. If you don't want to add another level of nesting, you can loop on a 'template' element.
<template v-for="item in items">
// Note the key is defined on real element, and not on template
<item-element v-if='condition' :key="item.key"></item-element>
</template>

Handlebars VueJS escape img src

To use VueJS data variables in my hbs view engine I need to add this \ before the variable so it looks like this for example \{{name}} - this would show the name from vue data variable name.
Now I cannot find a way to do this with img src.
<div v-for="item in itemsImgArr">
<img src="{{item.img}}">
\{{item.img}} - returns me a normal img link
</div>
I have tried this option: <img src="\" + "{{ item.img }}"> but it doesn't work. I've tried to experiment but I cannot get the link. Maybe someone could help ?
So if anybody uses Handlebars with VueJS you can show images like this:
<img :src="item.img"> and it works perfectly!

Can't get ViewContext.RouteData.Values["Controller"] to work for me

I am doing something wrong, that much I know. :) I am trying to display a simple breadcrumb on a page. I have this in a view:
#if (ViewContext.RouteData.Values["Action"].ToString() == "Index")
{
<li>
// This displays "Matter"
#ViewContext.RouteData.Values["Controller"]
</li>
}
else
{
<li>
// This displays a hyperlink "Matter",
// but the Href goes to "MyApp/Matter/Matter"
<a href="#ViewContext.RouteData.Values["Controller"].ToString()">
#ViewContext.RouteData.Values["Controller"]
</a>
</li>
}
In the above scenario, I have my Route.cs file set up to be "MyApp/Matter" which corresponds to an "Index" action on my "MatterController".
Clicking the link brings you to "MyApp/Matter/Matter" which does not work.
Any thoughts on how I can get this to work?
You're setting a relative path in the anchor tag. It's evaluating to:
Matter
That (Matter) gets appended to your current URL which, in this case, I can only assume is "MyApp/Matter". The result is "MyApp/Matter/Matter".
You need to specify an absolute URL or a more complete relative URL -- ../Matter would work in this case.
Beyond that, I can't help you without understanding a little more about what you're trying to do.
Where do you want the breadcrumb to take them? What's in the breadcrumb in relation to what they're looking at?
Is MyApp in your example the directory that contains the app or is it an area within your application?
I can only gather that Matter is the controller, but what's the action? If you're getting a link displayed then it's not currently looking at the Index action.