I'm working on this app and the idea is to show details of the cars in a sidebar on click. There are several issues like the sidebar is showing four times and I resolve it somehow but I don't know why is it showing four times. now I don't getting any response on emit call help me out please, I try $parent.$emit, $root.$emit but not seems working!!!
<template>
<div class="home">
<!-- warehouse details -->
<div
v-for="(detail, detailindex) in details"
:key="detailindex"
class="container mt-5 mb-5"
>
<h1>
{{ detail.name }}
<span class="location">{{ detail.cars.location }}</span>
</h1>
<!-- vehicle details -->
<SingleGarage :detail="detail"> </SingleGarage>
</div>
<b-sidebar
id="my-sidebar"
title="Sidebar with backdrop"
backdrop-variant="dark"
ref="mySidebar"
backdrop
shadow
#emitData="testingEmit()"
>
<div class="px-3 py-2">
<h1>{{currentCar}}</h1>
</div>
</b-sidebar>
</div>
</template>
<script>
// # is an alias to /src
import axios from "axios";
import SingleGarage from "../components/SingleGarage";
export default {
components: { SingleGarage },
name: "Home",
data: () => ({
details: String,
currentCar: 'String',
}),
methods:{
testingEmit(data){
this.currentCar = data
console.log('data from emit',data)
}
},
mounted() {
axios
.get("https://api.jsonbin.io/b/5ebe673947a2266b1478d892")
.then((response) => {
var results;
response.data.forEach((element) => {
element.cars.vehicles.sort((a, b) => {
a = new Date(a.date_added);
b = new Date(b.date_added);
results = a > b ? -1 : a < b ? 1 : 0;
return results * -1;
});
});
this.details = response.data;
});
},
};
</script>
<template>
<div class="vGrid mt-4">
<div
class="gridItem border vehicle singleCar"
v-for="(vehicle, vehicleIndex) in detail.cars.vehicles"
:class="'griditem' + vehicleIndex"
:key="vehicle._id"
>
<SingleCar
:vehicle="vehicle"
#click.native="testingTef(vehicleIndex)"
></SingleCar>
</div>
</div>
</template>
<script>
import SingleCar from "#/components/SingleCar";
export default {
name: "SingleGarage",
components: { SingleCar },
props: ["detail"],
data: () => ({
dummyImg: require("#/assets/img/dummycar.png"),
currentCar : 1
}),
methods: {
testingTef(vehicleIndex) {
this.$parent.$emit('emitData',this.detail.cars.vehicles[vehicleIndex].make)
this.$root.$emit('bv::toggle::collapse', 'my-sidebar')
console.log(this.detail.cars.vehicles[vehicleIndex].make)
console.log(this.detail.cars.vehicles[vehicleIndex].date_added)
this.currentCar = this.detail.cars.vehicles[vehicleIndex].make;
},
},
};
</script>
<template>
<div class="singleCar">
<!-- conditionally show image -->
<img
class="carImg"
:src="vehicle.img"
v-if="vehicle.img"
alt="No Preview"
/>
<img class="carImg" :src="dummyImg" v-else alt="No Preview" />
<div class="p-3">
<h3 class="make">{{ vehicle.make }}</h3>
<div class="modelDetails">
<div class="model d-flex ">
<p class="bold">Model:</p>
<p class="price ml-auto ">{{ vehicle.model }}</p>
</div>
<div class="price d-flex ">
<p class="bold">Price:</p>
<p class="price ml-auto ">€{{ vehicle.price }}</p>
</div>
</div>
<p class="dateAdded ml-auto ">{{ vehicle.date_added }}</p>
</div>
</div>
</template>
<script>
export default {
name: "SingleCar",
props: ["vehicle"],
data: () => ({
dummyImg: require("#/assets/img/dummycar.png"),
}),
methods:{
working(){
console.log('working');
console.log(this.vehicle.make)
}
}
};
</script>
Thanks for your help.
So a few things you can try to fix this
in your Home.vue you can change
#emitData="testingEmit()"
to
#emitData="testingEmit"
// or
#emitData="testingEmit($event)"
You are telling to the function testingEmit that is not params to parse. So you need to take out the () and Vue will parse everything that comes from the $event or you cant say put the $event as a param in your testingEmit (second option).
For your SingleGarage.vue you can take the $parent.$emit and replace it with
this.$emit('emitData',this.detail.cars.vehicles[vehicleIndex].make)
Related
Guys
I want to do a v-for using a component that has two differents props
COMPONENT
<template>
<div class="bg-light rounded p-2 px-5">
<h5> {{ cardNumber }}</h5>
<h3>{{ cardItem }}</h3>
</div>
</template>
<script>
export default {
name: 'HighlightCard',
props: ['cardItem', 'cardNumber']
}
</script>
V-FOR INSIDE OTHER COMPONENT
<template>
<div class="row m-auto">
<HighlightCard
v-for="(itemCard, index) in cardItems"
:key="index"
:cardItem="itemCard"
class="col m-3"/>
</div>
</template>
<script>
import HighlightCard from './HighlightCard.vue';
export default {
name: 'TopDashboard',
components: {
HighlightCard
},
data () {
return {
cardItems: ['Impressões', 'Cliques', 'Conversões', 'Custo'],
cardNumbers: ['2.300', '259', '45', 'R$ 350,00']
}
}
}
</script>
Is there any way to also add the cardNumber using v-for? It works fine the way it is, but I wanna use the both props, not just the ItemCard
If I understood you correctly , try to return right number with index:
Vue.component('highlightCard', {
template: `
<div class="bg-light rounded p-2 px-5">
<h5> {{ cardNumber }}</h5>
<h3>{{ cardItem }}</h3>
</div>
`,
props: ['cardItem', 'cardNumber']
})
new Vue({
el: "#demo",
data () {
return {
cardItems: ['Impressões', 'Cliques', 'Conversões', 'Custo'],
cardNumbers: ['2.300', '259', '45', 'R$ 350,00']
}
},
methods: {
num(val) {
return this.cardNumbers[this.cardItems.findIndex(i => i === val)]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div class="row m-auto">
<highlight-card
v-for="(itemCard, index) in cardItems"
:key="index"
:card-item="itemCard"
:card-number="num(itemCard)"
class="col m-3"/>
</div>
</div>
I have a web app which shows the blog posts in a grid. But the BlogCards component in the Home.vue just outputs nothing, whereas it should output the blogs in a grid format. All the datas are stored in firebase. If I go to /blogs, I can see the blogs in grid format, but it doesn't work on the Home.vue. It also spits out the Vue Warn: property or method "blogPostsCards" is not defined on the instance but referenced during render.
I took this code from this tutorial at 5:31:05 minute mark.
Any solution to this problem.
Home.vue
<template>
<div class="home">
<BlogPost :post="post" v-for="(post, index) in blogPostsFeed" :key="index" />
<div class="blog-card-wrap">
<div class="container">
<h3>View more recent blogs</h3>
<div class="blog-cards">
<BlogCards :post="post" v-for="(post, index) in blogPostsCard" :key="index" />
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import BlogPost from '../components/BlogPost.vue'
import BlogCards from '../components/BlogCards.vue'
export default {
name: "Home",
components: {
BlogPost,
BlogCards,
Arrow
},
computed : {
blogPostsCards() {
return this.$store.getters.blogPostsCards;
},
blogPostsFeed() {
return this.$store.getters.blogPostsFeed;
},
}
};
</script>
BlogCards.vue
<template>
<div class="blog-card">
<img :src="post.blogCoverPhoto" alt="">
<div class="info">
<h4>{{ post.blogTitle }}</h4>
<h6>Posted on: {{ new Date(post.blogDate).toLocaleString('en-us', {dateStyle: "long"})}}</h6>
<router-link class="link" to="#" >
View Post <Arrow class="arrow" />
</router-link>
</div>
</div>
</template>
<script>
export default {
name: "blogCard",
props: ["post"],
computed: {
editPost() {
return this.$store.state.editPost
},
}
}
</script>
And getter function in store/index.js
getters:{
blogPostsFeed(state){
return state.blogPosts.slice(0,2);
},
blogPostsCards(state) {
return state.blogPosts.slice(2,6);
},
},
<BlogCards :post="post" v-for="(post, index) in blogPostsCard" :key="index" />
In your Home.vue >> change blogPostsCard to blogPostsCards because you use blogPostsCards in your computed so it gives you that error.
I'm using vue cli and I have function that updates text #click but it keeps running multiple times:
User.vue
<div #click="newText('Volume')">
<Chart :text=text ></Chart>
volume
</div>
<div #click="newText('Temperature')">
<Chart :text=text ></Chart>
temp
</div>
<div #click="newText('Weight')">
<Chart :text=text ></Chart>
weight
</div>
<script>
newText: function(argT) {
const text = argT;
this.text = text;
console.log('text', this.text);
</script>
},
In Chart component when I console.log it ran 9 times!
props: ['text'],
text1(){
console.log('text', this.text)
},
It seems that since my User component is displayed 3 times(intentionally due to an array of 3 users I have) and there is a box for each measurement(temp, vol and weight), that's why it's 9 times. But I'm not sure why it runs each time.
I would like it to run only once for the box I clicked.
Any help would be great, thanks!
Update (additional code)
User.vue
<template >
<div class="user">
<div v-for="(item, index) in users" :key="item.id">
<div>
<div #click.stop="myFunction(index); newData(index, item.Vol); newText('Volume')">
<v-touch v-on:doubletap="isOpen = !isOpen;" >
<transition name="modal">
<div v-if="isOpen">
<div class="overlay" #click.self="isOpen = false;">
<div class="modal">
<Chart :text=text :dat=dat ></Chart>
</div>
</div>
</div>
</v-touch>
volume </div>
<div #click.stop="myFunction(index);newData(index, item.Temp); newText('Temperature')">
<v-touch v-on:doubletap="isOpen = !isOpen;" >
<transition name="modal">
<div v-if="isOpen">
<div class="overlay" #click.self="isOpen = false;">
<div class="modal">
<Chart :text=text :dat=dat ></Chart>
</div>
</div>
</div>
</v-touch>
temp </div>
<div #click.stop="myFunction(index); newData(index, item.Weight); newText('Weight')">
<v-touch v-on:doubletap="isOpen = !isOpen;" >
<transition name="modal">
<div v-if="isOpen">
<div class="overlay" #click.self="isOpen = false;">
<div class="modal">
<Chart :text=text :dat=dat ></Chart>
</div>
</div>
</div>
</v-touch>
weight</div>
</div>
</div>
</div>
</template>
<script>
/* eslint-disable */
import Charts from './Charts'
export default {
name: 'User',
components: {
Charts,
},
methods:{
newData: function(arrIndex, event) {
const dat = event;
this.dat = dat;
},
newText: function(argT) {
const text = argT;
this.text = text;
console.log('text', this.text);
},
myFunction: function (arrIndex) {
const name = this.users[arrIndex].name;
this.name = name;
},
},
}
</script>
Charts.vue
<div class="tabs">
<a v-on:click="activetab=1" v-bind:class="[ activetab === 1 ? 'active' : '' ]">Settings</a>
<a v-on:click="activetab=2" v-bind:class="[ activetab === 2 ? 'active' : '' ]">Chart</a>
</div>
<div class="content">
<div v-if="activetab === 1" class="tabcontent">
<Settings></Settings>
</div>
<div v-if="activetab === 2" class="tabcontent">
<Chart :dat=dat :text=text ></Chart >
</div>
</template>
<script>
import Chart from './Chart'
import Settings from './Settings'
/* eslint-disable */
export default {
name: 'Charts',
props: ['activetab', 'dat','text' ],
components: {
Settings,
Chart,
},
methods: {
text1(){
console.log('text', this.text)
},
</script>
and finally I pass text to a chart:
<template>
<div id="container" ref="chart"></div>
</template>
<script>
title: {
text: this.text,
}
series: [ {
name: this.text,
data: this.dat,
}],
In my case browser-sync was the problem.
The component I have below allows a user to view a products macro nutrient info and then also modify the serving size which in return updates the macro nutrient amounts.
The issue I'm having is that Im not getting the values to be updated correctly even when using vue set.
I'm using a watcher to run the calcNewNutriValues function.
<template>
<div class="product">
<div class="topbar">
<div class="left">
<p class="left__name">{{ product.name }}</p>
<p class="left__energy">{{ product.energy }}</p>
</div>
<div class="right">
<button class="cancel" #click="removeItem">
<inline-svg
:src="require('../assets/svg/addition-icon.svg')"
></inline-svg>
</button>
</div>
</div>
<div class="details">
<div class="macros">
<p class="details__heading">Macros</p>
<div class="macros__container container">
<div class="wrapper" v-for="(macro, name, index) in product.macros" :key="index">
<p>{{ name }}</p>
<p>{{ product.macros[name] }}</p>
</div>
</div>
</div>
<div class="serving">
<p class="details__heading">Serving Size (g)</p>
<input type="number" placeholder="40" v-model.number="productServSize">
</div>
</div>
</div>
</template>
export default {
data () {
return {
productServSize: 0,
ogServSize: 0,
macros: {
protein: '',
carbs: '',
fats: '',
fibre: ''
},
micros: {},
energy: ''
}
},
props: [
'product',
],
methods: {
serving () {
const num = this.product.servingSize.split(' ')[0]
this.productServSize = parseFloat(num)
this.ogServSize = parseFloat(num)
},
removeItem () {
this.$emit('removeProduct', this.product)
},
calcNewNutriValues () {
Object.keys(this.product.macros).forEach(key => {
let num = parseFloat(this.product.macros[key].split(' ')[0])
let perGram = parseFloat(num / this.ogServSize)
let newTotal = `${(perGram * this.productServSize).toFixed(1)} g`
this.$set(this.macros, key, newTotal)
})
}
},
mounted () {
this.serving()
Object.assign(this.macros, this.product.macros)
this.energy = this.product.energy
},
watch: {
productServSize: {
handler () {
this.calcNewNutriValues()
this.$emit('updatedNutriValues', this.product)
}
}
}
}
It only seems like macros isn't updating because your template displays product.macros instead of macros:
<div class="wrapper" v-for="(macro, name, index) in product.macros" :key="index">
<p>{{ name }}</p>
<!-- <p>{{ product.macros[name] }}</p> DON'T DO THIS -->
<p>{{ macros[name] }}</p>
</div>
demo
How would I show line space in vue.js. Right now everything is after each other....
Already tried this:
https://laracasts.com/discuss/channels/vue/vuejs-how-to-return-a-string-with-line-break-from-database
But nothing seems work. Trying this for 3 days now -_-.
I'm using Vue.js 1.0 and browserify.
Thanks a lot!
--EDIT--
<template>
<div>
<bar :title="title" />
<div class="Row Center">
<div class="Message Center" v-if="!loading">
<div class="Message__body" v-if="messages">
<div class="Message__item__body" v-for="message in messages" v-link="{ name: 'Message', params: { message: message.slug }}">
<div class="Message__item__body_content">
<p class="Message__title">{{ message.subject }}</p>
</div>
<div class="Message__item__body_content">
<p>Reacties: {{ message.totalReactions }}</p>
</div>
<div class="Message__item__body_content">
<p>Door: {{ message.user.name }} {{ message.user.last_name }}</p>
</div>
</div>
<pagination :last-page="lastPage" :page="page" :name="Message" />
<p v-if="noMessages" class="Collection__none">Er zijn momenteel geen berichten voor het topic {{ topic.name }}.</p>
</div>
</div>
<div class="Loader" v-if="loading">
<grid-loader :loading="loading" :color="color" :size="size" />
</div>
</div>
<div class="Row center" v-if="!loading && page == 1 && topic">
<div>
<button type="submit" class="Btn Btn-main" v-link="{ name: 'NewMessage', params: { topic: topic.slug }}">Nieuw bericht</button>
</div>
</div>
</div>
</template>
<script>
import Bar from '../Shared/Bar.vue';
import Pagination from '../Shared/Pagination.vue';
import Topic from '../../Services/Topic/TopicService';
import { GridLoader } from 'vue-spinner/dist/vue-spinner.min.js';
export default {
components: { Bar, Pagination, GridLoader },
data () {
return {
title: 'Berichten',
messages: [],
topic: null,
noMessages: false,
loading: false,
color: "#002e5b",
page: 1,
lastPage: 1,
}
},
route: {
data ({ to }) {
this.loading = true;
this.page = to.query.page || 1;
Topic.show(this.$route.params.topic, this.page)
.then((data) => {
this.topic = data.data.topic;
if(!data.data.messages.data.length == 0) {
this.messages = data.data.messages.data;
this.lastPage = data.data.messages.last_page;
} else {
this.noMessages = true;
}
this.loading = false;
});
}
}
}
</script>
When I do it like this:
<div class="Message__body__message">
<p>{{ message.message.split("\n"); }}</p>
</div>
It only adds comma's.
--EDIT--
Set container white-space style to pre-line, as in:
<div style="white-space: pre-line;">{{textWithLineBreaks}}</div>
When you split the message, you get multiple data items, which you should handle with a v-for.
But also see LMK's answer wherein you don't have to split the message.
new Vue({
el: '#app',
data: {
message: `this is a message
it is broken across
several lines
it looks like a poem`
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.min.js"></script>
<div id="app">
<template v-for="line in message.split('\n')">{{line}}<br></template>
</div>
You have to transform your data before rendering it with Vue.
const lines = stringWithLineBreaks.split('\n')
// then render the lines
I can give a more specific answer if you share the code you're working with.