I'm completely new to VueJS and am trying to create a project tile list with different data values per tile. I use Vue CLI. I created a component which is my template for one project tile.
component TheProjectTile.vue :
<template>
<router-link to="{{ project.url }}">
<div
class="row project-container"
style="background-color: {{ project.backgroundcolor }};"
v-scrollanimation
>
<div class="column column-60">
<h2>{{ project.title }}</h2>
<div class="button">view</div>
</div>
<div class="column">
<img src="#/assets/img/{{ project.image }}" alt="{{ project.title }}" />
</div>
</div>
</router-link>
</template>
<script type="text/javascript">
export default {
props: { project: Object },
data() {
return {}
}
}
</script>
Then I have my View on my Vue CLI application where I want to render the project tiles and where I want to give the data to the tiles:
View where the projects should be shown
<template>
<div id="projekte">
<section class="container">
<div id="projects">
<projectlist v-for="project in projects" :project="project" />
</div>
</section>
</div>
</template>
<script>
import TheProjectTile from './components/TheProjectTile'
export default {
components: {
projectlist: TheProjectTile
},
data() {
return {
projects: [
{
url: '/projekte/client1',
backgroundcolor: '#005ca9',
title: 'Website client 1',
img: 'client1.png'
},
{
url: '/projekte/client2',
backgroundcolor: '#c10b25',
title: 'Website client 2',
img: 'client2.png'
}
]
}
}
}
</script>
What do I need to change that it works? :/
Please take a look at following snippet:
You need to bind data with v-bind or :,
in v-for loop you need key
Vue.component('projectList', {
template: `
<a :to="project.url">
<div
class="row project-container"
:style="{'background-color': project.backgroundcolor}"
>
<div class="column column-60">
<h2>{{ project.title }}</h2>
<div class="button">view</div>
</div>
<div class="column">
<img :src="'#/assets/img/'+project.image" :alt="project.title" />
</div>
</div>
</a>
`,
props: { project: Object },
})
new Vue({
el: '#demo',
data() {
return {
projects: [{url: '/projekte/client1', backgroundcolor: '#005ca9', title: 'Website client 1', img: 'client1.png'}, {url: '/projekte/client2', backgroundcolor: '#c10b25', title: 'Website client 2', img: 'client2.png'}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div id="projekte">
<section class="container">
<div id="projects">
<!-- π key -->
<project-list v-for="(project, index) in projects" :key="index" :project="project" />
</div>
</section>
</div>
</div>
Related
I would like to translate the titles that are passed to my component via props. However I assume because my strings are being passed via props they are not being translated like the rest of my code. Below you will find my current 2 components that I am working with:
Parent Component:
`<setting-section
:title="$t('Random Text 1')"
:description="$t('Random Text 2')"
>`
In the Child:
`<template>
<div class="flex grid w-full">
<div class="divider mr-4 mt-5" />
<div class="header col-2">
<div class="title text-primary">{{ title }}</div>
<div class="description text-xs">{{ description }}</div>
</div>
<div class="flex col-10" v-if="!isLoading">
<slot />
</div>
<div class="flex col-10" v-else>
<Skeleton height="5rem" />
</div>
</div>
</template>
<script>
export default {
name: 'Menu',
props: {
title: {
type: String,
default: '',
},
description: {
type: String,
default: '',
},
},
};
</script>`
How ever if I do add the below variation it obviously wont work.
`<template>
<div class="flex grid w-full">
<div class="header col-2">
<div class="title text-primary">{{ $t('title')}} </div>
<div class="description text-xs">{{ description }}</div>
</div>
</div>
</template>`
Your both the solutions should work as we always configured VueI18n at global level. Hence, translation literals always accessible from any nested component.
Live Demo as per both the use cases :
Vue.component('child-one', {
props: ['childmsg'],
template: '<p>{{ childmsg }}</p>'
});
Vue.component('child-two', {
template: `<p>{{ $t('message') }}</p>`
});
Vue.use(VueI18n);
const i18n = new VueI18n({
locale: 'ja',
fallbackLocale: 'en',
messages: {
"ja": {
"message": "γγγ«γ‘γ―γδΈη"
},
"en": {
"message": "Hello World"
}
}
});
new Vue({
el: "#app",
i18n,
data() {
return {
locale: "ja"
}
},
watch: {
locale(newLocale) {
this.$i18n.locale = newLocale;
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.8/dist/vue.min.js"></script>
<script src="https://unpkg.com/vue-i18n#8.8.2/dist/vue-i18n.min.js"></script>
<main id="app">
<div>
<label><input type="radio" value="ja" v-model="locale" />Japanese</label>
<label><input type="radio" value="en" v-model="locale" />English</label>
</div>
<h3>Passing translated string from parent</h3>
<child-one :childmsg="$t('message')"></child-one>
<h3>Transaltions happens in child component itself</h3>
<child-two></child-two>
</main>
I'm trying to share data stored in a variable favorite_count within the Favorites component in Favorites.vue file. I want to share that data with the App Component in the App.vue file but I'm not able to. I would want that if I change the value of favorite_count in the Favorites component, it changes in the App Component. Done quite some research on the web but no success yet. Any ideas on what I could be doing wrong?
Favorites.vue file
<template>
<div class="row m-5">
<h3 class="col-8">Your Favorites</h3>
<div class="col-4">
<p class="pull-right m-1">Picks
<span >{{ favorite_count }}</span> / 5</p>
</div>
<hr>
</div>
</template>
<script>
export default {
name: 'favorites',
data() {
return {
favorite_count: 5,
}
},
methods: {
changeFavoriteCount() {
this.favorite_count = this.favorite_count + 2;
},
emitToParent (event) {
this.$emit('childToParent', this.favorite_count)
}
}
}
</script>
App.vue file
<template>
<div class="navbar navbar-expand-md navbar-dark bg-primary">
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav">
<li class="nav-item">
<router-link to="/favorites" class="btn btn-info">
Favorites ( {{ favorite_count }} )
</router-link>
</li>
</ul>
</div>
</div>
</template>
<script>
import Favorites from './components/Favorites.vue'
export default {
name: 'App',
components: {
Favorites
},
data () {
return {
favorite_count: 0,
}
}
}
</script>
If you are going to use <router-view> later in your application, I would suggest this solution
If you were going to include Favorites inside <template> in App.vue, you can use props:
1. Declare your 'shared' variable in the parent component (App.vue)
data () {
return {
favorite_count: 0,
}
},
2. Define props in your child component (Favorites.vue)
export default {
props: { favorite_count: Number },
...
}
3. Pass favorite_count as prop to Favorites
<template>
...
<Favorites :favorite_count="favorite_count" ... />
</template>
If you will need to update favorite_count - emit an event to parent component. More about it in Vue docs
Edit: Just to clarify: If you are going to update favorite_count from Favorites.vue, you need to emit an event to App.vue to avoid mutating props.
That also means you need to move your changeFavoriteCount() function to App.vue and apply a listener to your child component which will call this function:
// App.vue
<template>
...
<Favorites
#your-update-event="changeFavoriteCount"
:favorite_count="favorite_count" ...
/>
</template>
...
changeFavoriteCount(newVal) {
this.favorite_count = newVal;
},
change your Favourite.vue file like this
<template>
<div class="row m-5">
<h3 class="col-8">Your Favorites</h3>
<div class="col-4">
<p class="pull-right m-1">
Picks <span>{{ favorite_count }}</span> / 5
<button #click="changeFavoriteCount">Click me to change favorite_count</button>
</p>
</div>
<hr />
</div>
</template>
<script>
export default {
name: "favorites",
data() {
return {
favorite_count: 5,
};
},
methods: {
changeFavoriteCount() {
this.favorite_count = this.favorite_count + 2;
this.emitToParent();
},
emitToParent() {
this.$emit("childToParent", this.favorite_count);
},
},
};
</script>
and the App.vue file like this
<template>
<div class="navbar navbar-expand-md navbar-dark bg-primary">
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav">
<li class="nav-item">
<router-link to="/favorites" class="btn btn-info">
<Favorites #childToParent="updateFavorite" />
Favorites ( {{ favorite_count }} )
</router-link>
</li>
</ul>
</div>
</div>
</template>
<script>
import Favorites from './components/Favorites.vue'
export default {
name: 'App',
components: {
Favorites
},
data () {
return {
favorite_count: 0,
}
},
methods: {
updateFavorite(data) {
this.favorite_count = data;
},
},
}
</script>
I am trying to send a dynamic src as prop to imageComponent, but i am doing it wrong. fileName = about.gsx$imagesrc.$t does not work. The images are stored in asset/Pictures and about.gsx$imagesrc.$t is the same value as the image name.
<template>
<div class="timeline">
<div class="timeline-content" v-for="about in state.aboutData" :key="about.index">
<div class="fill-circle">
<h2 class="timeline-year" > {{about.gsx$year.$t}}</h2>
</div>
<p class="timeline-text" > {{about.gsx$happening.$t}} </p>
<ImageComponent
//Filename is the problem
fileName= about.gsx$imagesrc.$t
leftPosition="200px"
activeColor="#132766"
/>
</div>
</div>
</template>
<script>
import { state } from '#/store/index.js'
import ImageComponent from "#/components/UI-kit/PictureModules/Sko.vue"
export default {
name:"Timeline",
components: {ImageComponent},
}
The Image component
<template>
<div class="ImageComponent" v-bind:style="{ left: leftPosition}">
<img class="image" :src="require(`#/assets/Pictures/${fileName}`)">
<div class="shadow" v-bind:style="{ backgroundColor: activeColor}"></div>
</div>
</template>
<script>
export default {
name:"ImageComponent",
props: {
activeColor: [String],
leftPosition: [String],
fileName: [String],
}
}
</script>
This is the error i get
Error in render: "Error: Cannot find module './about.gsx$imagesrc.$t'"
I am building a small application on VueJS where I am having a api which gives information about the components to be loaded while rendering the page.
I have setup vue-router as:
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
export const router = new VueRouter({
routes:
[
{
path: '/',
component: Vue.component('welcome', () => import('../Components/Admin/Login.vue')),
name: 'login'
},
{
path: '/:page',
component: Vue.component('dashboard', () => import('../Components/Admin/Dashboard/Dashboard.vue')),
name: 'dashboard'
},
]
});
Now this dashboard component asynchronously calls the component to be loaded, something like this:
<template>
<div>
<header>
<nav class="navbar has-shadow">
<div class="container">
<div class="navbar-brand">
<a class="nav-item is-centered">
<img src="nits-assets/images/logo.png" alt="NitsEditor Logo" width="170" height="50">
</a>
</div>
<div class="navbar-menu">
<div class="navbar-end is-centered">
<div class="navbar-item">
<p class="control"><a class="button is-primary is-outlined is-rounded">Log out</a></p>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="section" id="dashboard">
<div class="columns">
<aside class="column is-2 menu-section">
<nav class="menu is-centered">
// Menu section
</nav>
</aside>
<main class="column" id="main-section">
<page-title :title="title"></page-title>
<div class="columns is-multiline">
<div class="column">
<top-seller-widget></top-seller-widget>
</div>
</main>
</div>
</div>
</div>
</template>
<script>
export default {
name: "dashboard",
data() {
return {
pageComponents: '',
title: '',
description: ''
}
},
components: {
'PageTitle': () => import('./PageTitle'),
'TopSellerWidget': () => import('./TopSellerWidget')
},
created() {
axios.get('/api/page-components?slug='+this.$route.params.page).then(response => {
if(response.status === 200)
{
this.title = response.data.page.title
console.log(response.data)
}
})
}
}
</script>
<style scoped>
// Some styling
</style>
As you can see I am trying to import components in component section asynchronously:
components: {
'PageTitle': () => import('./PageTitle'),
'TopSellerWidget': () => import('./TopSellerWidget')
},
And calling the components inside the template:
<div class="section" id="dashboard">
<div class="columns">
<aside class="column is-2 menu-section">
<nav class="menu is-centered">
// Menu section
</nav>
</aside>
<main class="column" id="main-section">
<page-title :title="title"></page-title>
<div class="columns is-multiline">
<div class="column">
<top-seller-widget></top-seller-widget>
</div>
</main>
</div>
</div>
Now while getting the axios call data:
I get in this format:
{
components: [
{name: 'PageTitle', location:'./PageTitle', 'data': {title: 'Dashboard'}},
{name: 'TopSellerWidget', location:'./TopSellerWidget', 'data': NULL}
]
}
Then I checked whether I can load my components when we get a response:
axios.get('/api/page-components?slug='+this.$route.params.page).then(response => {
if(response.status === 200)
{
this.title = response.data.page.title
if(response.data.page.content)
{
Vue.component('PageTitle', () => import('./PageTitle'))
Vue.component('TopSellerWidget', () => import('./TopSellerWidget'))
}
console.log(response.data)
}
})
It worked fine, but when I'm trying to make it dynamic:
axios.get('/api/page-components?slug='+this.$route.params.page).then(response => {
if(response.status === 200)
{
this.title = response.data.page.title
if(response.data.page.content)
{
response.data.page.content.components.forEach(function (val, index) {
Vue.component(val.name, () => import(val.location))
})
}
console.log(response.data)
}
})
I am getting errors:
And in console I get:
What can I do in such condition?
I think you almost got the answer yourself. The error log probably says that import(val.location) is importing an dependency but the dependency is an expression. So you should replace it with a name instead, like you did in your experiment.
Also, I am not sure if it is necessary to asynchronously import the two components (PageTitle and TopSellerWidget) inside Dashboard. Dashboard itself is already loaded asynchronously, so any of its dependencies, such as PageTitle is also loaded only when you request Dashboard. And since you need both PageTitle and TopSellerWidget to properly render your Dashboard, you may as well get them along with Dashboard, rather than spending one more round trip on the wire.
I'm creating a basic MTG Deckbuilder using Vue.Js. I'm trying to have the user type the card name into an input box then when the button is clicked, the deck list is update with the card name. Currently,the list add's a blank element for the card instead of the card name. Any ideas?
app.Vue:
<template>
<div id="app">
<deckBuilder #addCard="addCard" :title="title" :card="card" :deck="deck" />
</div>
</template>
<script>
import deckBuilder from './components/deckBuilder'
export default {
name: 'app',
components: {
deckBuilder,
},
data: () => ({
title: 'MTG Deck Builder',
card: {
name: '',
},
deck:[],
}),
methods: {
addCard: function(event,) {
this.deck.push(this.card.name);
},
},
}
</script>
deckBuilder.Vue:
<template>
<div>
<h1>{{ title }}</h1>
<input v-model="card.name" placeholder="Type a Card Name" />
<p> the card is: {{ card.name }}
<button #click="addCard">Add!</button>
<h2>Deck</h2>
<ul>
<li v-for="item in deck">{{ item.card }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'deckBuilder',
props: ['title', 'card', 'deck'],
methods: {
addCard() {
this.$emit('addCard')
}
},
}
</script>
Because you push string item instead of object
this.deck.push(this.card.name);
Correct template will be {{ item }}, not {{ item.card }}
This is because you are not emitting any data in your $emit
Try this,
In deckbuilder.vue
addCard() {
this.$emit('addCard',this.card.name);
}
In app.vue
addCard: function(cardName){
this.deck.push(cardName);
}
In html, v-for should be this way
<li v-for="item in deck">{{ item }}</li>
Try This
<!-- Menu Content -->
<ul class="nav-list" style="overflow: visible;">
<!-- Items -->
<span v-for="(menuItem, index) in menuItems" :key="index">
<li>
<nuxt-link :to="menuItem.link" :class="menuItem.class">
<i class="bx" :class="menuItem.icon || 'bx-square-rounded'" />
<!-- Link Name -->
<span class="links_name">{{ menuItem.name }}</span>
</nuxt-link>
</li>
</span>
</ul>
<script>
export default {
name: 'SidebarMenu',
menuItems: {
type: Array,
default: () => [
{
link: '/',
name: '_home',
icon: 'bx-home',
class: '',
},
{
link: '/blog',
name: '_blog',
icon: 'bx-edit',
class: '',
},
{
link: '/projects',
name: '_projects',
icon: 'bx-code',
class: ''
},
{
link: '/about',
name: '_about',
icon: 'bx-user',
class: ''
},
],
},
}
</script>