how to deal with icons from assets in vue - vue.js

I try to use images, named from JSON data, which are located in my assets in Vue with:
My JSON:
cards: [
{
title: 'my Title'
image: 'myimagename.png'
style: 'color: green'
},
title: 'another Title'
image: 'myotherimagename.png',
style: 'color: red'
}
]
and then I try in it with:
<q-card :style="card.style" class="dashboard-card text-white q-mt-md" v-for="card in cards"
:key="card.id" style="height: 132px; width: 132px">
<q-card-section dense>
<q-img
:src="require('../assets/icons/' + card.image)"
basic
/>
<div class="dashboard-card-title"> {{ card.title }}</div>
</q-card-section>
</q-card>
but I always get a 404, how can I use the images in my assets folder?
Error: Cannot find module './myimagename.png'
at webpackContextResolve (eval at ./src/assets/icons sync recursive ^\.\/.*$ (0.js:218), <anonymous>:27:11)
at webpackContext (eval at ./src/assets/icons sync recursive ^\.\/.*$ (0.js:218), <anonymous>:22:11)

I had to use the public folder like public/images and access them with
:src="'/images/' + card.image"
all works now like expected.

You cannot require an image. Depending on your bundle solution, you should be able to just do this
<q-img :src="'../assets/icons/' + card.image)" basic />

Related

how to pass a text property to chat-message component in quasar-vue?

I'm trying to create a simple chat window using the Quasar framework
in my template, I have this
<div v-for="message in this.chatMessages" :key="message.id">
<q-chat-message
:name="message.name"
:text="message.text"
:sent="message.sent"
>
<slot name="avatar">
<q-avatar size="30">
<img alt="avatar" :src="message.avatar"/>
</q-avatar>
</slot>
</q-chat-message>
</div>
and in the data I have the following
data () {
return {
text: null,
fixed: false,
chatMessages: [
{
id: 123,
name: 'Support',
avatar: 'https://cdn.quasar.dev/img/avatar1.jpg',
text: ['hey, how are you?', ''],
sent: true
},
{
id: 456,
name: 'me',
avatar: this.$store.getters['xstore/getAvatar'],
text: ['doing fine, how r you?', ''],
sent: false
}
]
}
},
According to the documentation https://quasar.dev/vue-components/chat#introduction the component receives an array as text, like below
<q-chat-message
:text="['doing fine, how r you?']"
/>
but when I run it the text never appears on the screen, so, I'm not sure if I'm doing something wrong with the array properties, the rest of the attributes are working fine
How an array must be passed within a div v-for?
is there a magic trick?
If I hardcode the text message as below they work :(
:text="['This is a hardcoded message']"
this was how I solved it in case someone goes through the same
<div v-for="message in this.chatMessages" :key="message.id">
<q-chat-message
:avatar="message.avatar"
:name="message.name"
:sent="message.sent"
>
<div v-for="text in message.text" :key="text">
<div>
{{ text }}
</div>
</div>
</q-chat-message>
</div>
You are using the slot incorrectly. In this case, it is not needed at all, the avatar will be shown correctly. But if you want to use an avatar slot, it will look like this:
<template v-slot:avatar>
<img
class="q-message-avatar q-message-avatar--sent"
src="https://cdn.quasar.dev/img/avatar4.jpg"
>
</template>

Nuxt Menu links from API...How can i detect if its a Nuxt link :to or :href?

Im building my main menu from an API :
<b-navbar-nav>
<div v-for="result in resultsmenu" :key="result.id">
<span class="hoverlink">
<nuxt-link :to="result.slug">{{result.title}}</nuxt-link>
</span>
</div>
</b-navbar-nav>
Everythings works well but one problem is in the menu from the API ..One link is external with an "href" like : https://ww.instagram.com so nuxt-link process it like a internal route i end up with :
http://localhost:3000/https://ww.instagram.com
I was wondering if there is a way to tell Nuxt that if a link is an "href" type: "link" to handle it like an external link instead of an nuxt-link to: ?
Thank you
One way to achieve this would be to use a computed property.
Assuming your resultsmenu data looks something like...
resultsmenu: [
{slug: 'http://www.website.com', title: 'link to website.com'},
{slug: '/test', title: 'link to a website.com'},
{slug: '/yay', title: 'link to b website.com'},
{slug: 'http://www.website.com', title: 'link to c website.com'}
]
You can do...
computed: {
menuLinks() {
let links = []
this.resultsmenu.forEach(link => {
let menuItem = {}
menuItem.isHttp = !!link.slug.includes('http');
menuItem.target = link.slug
menuItem.title = link.title
links.push(menuItem)
})
return links
}
}
Then in your template:
<div v-for="(result, index) in menuLinks" :key="index">
<span>
<nuxt-link v-if="!result.isHttp" :to="result.target">{{result.title}}</nuxt-link>
<a v-else :href="result.target">{{result.title}}</a>
</span>
</div>

Dynamically rendering components from the same slot name

So I am making a simple stepper. I have my structure like so:
<stepper :steps="steps">
<template slot="stepper:step">
<div class="">
{{ first }}
</div>
</template>
<template slot="stepper:step">
<div class="">
{{ second }}
</div>
</template>
</stepper>
export default {
data: () => ({
steps: [
{ name: 'First step' },
{ name: 'second step' },
],
first: 'First content',
second 'second content',
})
}
My stepper is like so: https://gist.github.com/natecorkish/81e22edb9e41348e579b705c3a4d3e54
and my step is like so: https://gist.github.com/natecorkish/45108d046ddc7d116110c973b608a774
Now, I am get an errror when rendering the content:
vue.runtime.esm.js?2b0e:1888 TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
--- property '_renderProxy' closes the circle
at JSON.stringify ()
I have tried VueJS Render VNode but that only renders a couple of my divs/inputs. So, judging from my code, how can I fix this?

How can I add an href to a q-table (Quasar Data Table)?

I have put a q-table in my page to show my data. this is work correctly. I want to put an href in first column and another in last column. You should can click on them to go to other pages for showing details row and edit row Respectively.
Title: go to page /#/offer/uuid
Edit: go to page /#/account/offers/edit/uuid
<template>
<q-page>
<div class="row justify-center">
<q-table
:data="data"
:columns="columns"
row-key="id"
selection="single"
:selected.sync="selected"
:filter="filter"
:loading="loading"
>
</q-table>
</div>
</div>
</q-page>
</template>
<script>
.....
columns: [
{
name: 'title',
required: true,
label: 'Title',
align: 'left',
field: row => row.title,
sortable: true,
format: val => '' + val + '' //this is not work
},
{
name: 'category',
label: 'Category',
field: 'category',
sortable: true
},
{
name: 'payment',
label: 'Payment',
field: 'payment'
},
{
name: 'action',
label: 'Edit',
field: 'key',
format: val => '' + val + '' //this is not work
}
]
.....
</script>
This answer assumes Quasar 1.0.0-rc4. For earlier versions it may look a bit different but the crux of it is that you need to use scoped slots.
There are scoped slots called body-cell-[name] that can be used to render content that isn't plain text. Here the [name] portion should match the name for the corresponding column in your columns definition.
<q-table ...>
<template v-slot:body-cell-title="cellProperties">
<q-td :props="cellProperties">
{{ cellProperties.value }}
</q-td>
</template>
<template v-slot:body-cell-action="cellProperties">
<q-td :props="cellProperties">
{{ cellProperties.value }}
</q-td>
</template>
</q-table>
My use of v-slot assumes Vue 2.6.0+, for earlier versions you would use slot and slot-scope instead.
You haven't explained where the UUID part of your URL comes from so I haven't included that in the code above. I would imagine it is included somewhere in the row data, so in practice you would need something like :href="'#/offer/' + encodeURIComponent(cellProperties.row.uuid)".
If you're using a routing library such as Vue Router then there are alternatives to building URLs directly within <a> tags. You may wish to investigate further before sprinkling hand-crafted URLs throughout your application code. However, the use of scoped slots is likely to remain no matter how you implement your links.
Use :href. For example:
<a :href="'/app/product/'+props.row.productId">{{ props.row.name }}</a>

Can a Component be named from data?

I have three component icons <DiscoverIcon>, <FeedIcon>, <ProfileIcon> and in tab loop I want to be able to use a different Icon for each respective title.
I tried a list element like
{ key: 1, icon: <div class='iconbgd'><DiscoverIcon /></div>, text: 'Discover', route: '/discover'}
and calling {{ link.icon }} and also
{ key: 1, text: 'Discover', route: '/discover'}
and calling <div class='iconbgd'><{{link.text}}Icon /></div>
<template>
<v-tabs fixed-tabs>
<v-tab
v-for="link in links"
:key="link.key"
>
<div class='iconbgd'><{{link.text}}Icon /></div><h4>{{ link.text }}</h4>
</v-tab>
</v-tabs>
</template>
<script>
import DiscoverIcon from '../components/icons/DiscoverIcon'
import FeedIcon from '../components/icons/FeedIcon'
import ProfileIcon from '../components/icons/ProfileIcon'
export default {
components: {
DiscoverIcon,
FeedIcon,
ProfileIcon
},
name: 'App',
data () {
return {
links: [
{ key: 1, icon: <div class='iconbgd'><DiscoverIcon /></div>, text: 'Discover', route: '/discover'},
{ key: 2, icon: <div class='iconbgd'><FeedIcon /></div>, text: 'Feed', route: '/feed'},
{ key: 3, icon: <div class='iconbgd'><ProfileIcon /></div>, text: 'Profile', route: '/profile'}
]
}
}
}
</script>
<style>
.iconbgd svg{
fill:url(#grad1);
width: 30px;
height: auto;
padding-right: 5px;
}
</style>
This is the Vuetify tabs component for this use case but getting it working isn't connected with using tabs but my expected result is to be able to loop through and in each tab use a different correlated component rather than just create three separate buttons which I currently have.
First of all {{link.icon}} is not is meant to be displayed as HTML. You should use a different approach.
<div class='iconbgd'><{{link.text}}Icon /> is equal to <div class='iconbgd' v-text="link.text"><Icon />. Therefore Vue has a v-html directive for HTML, you can read here more about the varieties of directives.
Still try to avoid v-html, when possible and since the different {{link.icon}} are very similar you could make it easily work without v-html.
This looks like you are trying to bind components <{{link.text}}Icon />. Dynamic components are what you looking for and they are very powerful.
I quickly looked into the Vuetify documentation for v-tabs and changed it a bit, however I have never used it before and this is not tested. It should be what you are trying to accomplish:
<template>
<v-tabs fixed-tabs>
<v-tab v-for="link in links" :key="link.key">
<div class="iconbgd">{{link.label}}</div>
</v-tab>
<v-tab-item v-for="link in links" :key="link.key">
<h4>{{link.label}}</h4>
<component :is="link.label + 'Icon'" :key="link.key"/>
</v-tab-item>
</v-tabs>
</template>
<script>
import DiscoverIcon from '../components/icons/DiscoverIcon';
import FeedIcon from '../components/icons/FeedIcon';
import ProfileIcon from '../components/icons/ProfileIcon';
export default {
data() {
return {
links: [
{
key: 1,
label: 'Discover',
route: '/discover'
},
{
key: 2,
label: 'Feed',
route: '/feed'
},
{
key: 3,
label: 'Profile',
route: '/profile'
}
]
};
},
name: 'App',
components: {
DiscoverIcon,
FeedIcon,
ProfileIcon
}
};
</script>
<style>
.iconbgd svg {
fill: url(#grad1);
width: 30px;
height: auto;
padding-right: 5px;
}
</style>
Thank you so much! A few tweaks to that and it's working.
<v-tabs fixed-tabs color='transparent' slider-color='#1341B2'>
<v-tab v-for="link in links" :key="link.key" :to="link.route">
<div class="iconbgd">
<component :is="link.label + 'Icon'" :key="link.key"/>
</div>
<h4>{{link.label}}</h4>
</v-tab>
</v-tabs>