first of all I'm sorry for my bad English, I'm using a translator.
I'm a beginner with VUE and VUE X, there are surely big mistakes.
I have a problem with VUE, currently I am trying to display a publication thanks to its ID.
Here is my DATA :
data(){
return {
list: [this.$store.dispatch('allPublications')],
id:'',
feed: '',
}
},
Here is my STORE action:
publicationId:({commit}, messages) => {
instance.get('/publications/' + messages.id)
.then(function(response){
commit('setMessage', response.data.publication)
console.log(response)
this.feed = response.data.publication.data
})
.catch(function(error){
console.log(error)
})
},
Here is my computed:
computed: {
...mapState({
user: 'profileUser',
publication: 'publicationFeed',
message: 'publicationInfos'
}),
message(){
return this.$store.state.message;
},
},
Here is my state :
setMessage: function(state, message){
state.message = message
},
Here is my template :
<template>
<div class="card-body" #click="publicationId(message.id)">
<span class="badge bg-secondary">{{ message.User.username }}</span>
<div class="dropdown-divider"></div>
<div class="card-text d-flex justify-content-between align-items-md-center">
<p class="card-text d-flex flex-start">{{ message.message }}</p>
</div>
<span class="message__date">{{ message.createdAt.split('T')[0]}}</span>
</div>
<img class="card-img-top" alt="..." :src="message.image">
Some screenshot to help you more :
VUE google chrome tool
Before reloading the page, everything is OK
After reloading the page, everything is going wrong
Everything works fine as long as I don't reload the page, as soon as I reload it I get an error, my computed value disappears and I can't get the data from my computed.
I have searched a lot of information without being able to solve this problem, thanks to you for the help!
It seems that i've solved this issue doing this :
data() {
return {
componentLoaded: false,
list: [this.$store.dispatch('allPublications')],
id: '',
feed: '',
}
},
In the mounted :
mounted() {
this.componentLoaded = true;
this.id = this.$route.params.id;
this.$store.dispatch('publicationId', { id: this.$route.params.id })
},
In the computed :
computed: {
message() {
if (!this.componentLoaded) {
return null
} else {
return this.$store.state.message;
}
},
},
And I add a v-if in the template
<template>
<div class="verification" v-if="componentLoaded === true">
<div class="card-body" #click="publicationId(message.id)">
<span class="badge bg-secondary">{{ message.User.username }}</span>
<div class="dropdown-divider"></div>
<div class="card-text d-flex justify-content-between align-items-md-center">
<p class="card-text d-flex flex-start">{{ message.message }}</p>
</div>
<span class="message__date">{{ message.createdAt.split('T')[0] }}</span>
</div>
<img class="card-img-top" alt="..." :src="message.image" />
</div>
<div v-else>
<h1>test</h1>
</div>
It worked for me, I hope it will help for those who needs.
Related
In my project I use medium-zoom with pagination. On first page it works well but on second, third, fourth... I have to click several times for close image...on second page...two times, on third 3 times...
it seems to be a problem with maybe any index number?
Here is my code:
<template>
<div>
<div v-if="loading" class="text-center">
<i class="fas fa-spinner fa-pulse fa-5x"></i>
</div>
<div v-else>
<div v-for="(item, imageIndex) in pageOfItems" :key="item.id" class="m-3">
<div class="row mt-3">
<div class="col-lg-9 my-auto" v-html="item.mytext"></div>
<div class="col-lg-3 my-auto text-center">
<article class="container">
<img
class="img-thumbnail"
:src="'http://localhost:4000/api/galeria/' + item.galeriaId + '_f.jpg'"
/>
</article>
</div>
</div>
<hr class="hr1" />
</div>
</div>
<div class="pb-0 pt-3 text-center">
<jw-pagination :items="info" :page-size="10" #changePage="onChangePage"></jw-pagination>
</div>
</div>
</template>
<script>
import mediumZoom from 'medium-zoom'
import axios from 'axios'
export default {
data() {
return {
info: [],
customLabels,
pageOfItems: [],
loading: true,
}
},
mounted() {
axios
.get('http://localhost:4000/api/fetch_galeria.php/')
.then((response) => (this.info = response.data))
.finally(() => (this.loading = false))
},
updated() {
mediumZoom('article img', {
background: 'transparent',
})
},
methods: {
onChangePage(pageOfItems) {
// update page of items
this.pageOfItems = pageOfItems
},
},
}
</script>
You will pretty much need to detach the event listeners here. Because it should be a lot of them added everytime due to the updated hook.
A naive implementation would be to add mediumZoom on the mounted hook. And when you do have a new changePage event, to detach it from all the images, then to apply it to the new ones with the same mediumZoom call.
Below is a way to see which event listeners (and probably how many) you have linked to a specific VueJS component. Select it in the Vue devtools and then, you will have access to the element's properties via $vm0.
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)
I'm new to vue, and trying to follow a tutorial.
I'm trying to pull the image through that relates to the id of my article.
Everything else is coming through ok, article.id etc. The image will have the same filename as the article.id for the time being, so I just want to pull it into the component.
<div class="card bg-dark mb-2" v-for="article in articles" v-bind:key="article.id">
<div class="card-body">
<img class="card-img-top" v-bind:src="images/articles/`{{ $article.id }}`.jpg" width="100%" alt="Card image cap" />
<h5 class="card-title text-white">{{ article.id }}. {{ article.title }}</h5>
<h6 class="card-subtitle mb-2 text-white-50">{{ article.from }}</h6>
<p class="card-text text-truncate" style="max-width: 150px;">{{ article.description }}</p>
</div>
<div class="card-footer text-right">
<small class="text-white-50">Added by <span class="text-white">{{ article.added_by }}</span> ({{ article.created_at }})</small>
</div>
</div>
Please let me know if I need to provide anything else to this post.
Update:
I don't know if it makes a difference, but the article.id I'm using is being fetched from the Laravel API I've created.
The #app div is in in my index.blade.php file
export default {
data() {
return {
articles: [],
article: {
id: '',
title: '',
description: '',
from: '',
rating: '',
from: '',
created_at: '',
added_by: ''
},
recipe_id: '',
pagination: {},
edit: false
}
},
created() {
this.fetchArticles();
},
methods: {
fetchArticles(page_url) {
let vm = this;
page_url = page_url || '/api/articles'
fetch(page_url)
.then(res => res.json())
.then(res => {
this.articles = res.data;
vm.makePagination(res.meta, res.links);
})
.catch(err => console.log(err))
},
makePagination(meta, links) {
let pagination = {
current_page : meta.current_page,
last_page : meta.last_page,
next_page_url : links.next,
prev_page_url : links.prev
};
this.pagination = pagination;
}
}
A bound attribute is parsed as javascript. So if you want the string images/articles/123.jpg for article 123 you need to pass it to the :src attribute like so:
<img :src="`images/articles/${article.id}.jpg`" />
or
<img :src="'images/articles/' + article.id + '.jpg'" />
Mustaches cannot be used inside HTML attributes. Instead, use a v-bind directive (v-bind:src or :src)
You can bind the image src like this:
<img :src="'images/articles/' + article.id + '.jpg'" />
You can see this working on the screenshot of the fiddle I developed for your answer
Check out the Fiddle :)
I want the tag that currently says true or false, I want it to say "FREE" if it's free and say "PAID" if it's not.
https://www.eventbriteapi.com/v3/events/search/?location.address=45+Depot+Ave.++Bronx%2C+NY+10457&location.within=50mi&token=6RXWSSZPE4APEYSWTJJF
I'm getting a response from data.events.is_free in the form of a boolean that's true if free and false if not.
I know I have nothing between the v-if tags, but the whole thing goes blank if add anything.
HTML:
<div id="app" class="container">
<h1 id="header" class="title is-1 has-text-centered">Event Lookup for ECH</h1>
<div v-for="event in info">
<h2 class="title is-4" id="eventName">{{ event.name.html }} <span v-if="" class="tag is-success">{{ event.is_free }}</span></h2>
<div id="eventDescription">{{ event.description.text }}</div>
<div id="eventDateTime">{{ event.start.local }} - {{ event.end.local }}</div>
</div>
</div>
Vue / JS
// The plan is to make this more extensive later
// https://www.eventbriteapi.com/v3/events/search/?location.address=45+Depot+Ave.++Bronx%2C+NY+10457&location.within=50mi&token=6RXWSSZPE4APEYSWTJJF
// This is a random address...
const baseUrl = 'https://www.eventbriteapi.com/v3/events/search/?location.address=45+Depot+Ave.++Bronx%2C+NY+10457&location.within=50mi&token=6RXWSSZPE4APEYSWTJJF';
new Vue({
el: '#app',
data () {
return {
info: null
}
},
mounted () {
axios
.get(baseUrl)
.then(response => (this.info = response.data.events))
},
computed () {
isFree
if (response.data.events.is_free == true) {
return true;
}
else {
return false;
}
}
})
https://codepen.io/Mortiferr/pen/qyajJd
Here's a link to my Codepen.
You can use v-if and v-else.
<div id="app" class="container">
<h1 id="header" class="title is-1 has-text-centered">Event Lookup for ECH</h1>
<div v-for="event in info">
<h2 class="title is-4" id="eventName">{{ event.name.html }}
<span v-if="event.is_free" class="tag is-success">Free</span>
<span v-else class="tag is-success">Paid</span>
</h2>
<div id="eventDescription">{{ event.description.text }}</div>
<div id="eventDateTime">{{ event.start.local }} - {{ event.end.local }}</div>
</div>
</div>
You don't need a computed property for this. You can use v-if and v-else.
Alternatively, if you know that you will only have the text "FREE" or "PAID" without any markup needed, you might want to consider just using a ternary expression:
<span class="tag is-success">{{event.is_free ? "FREE" : "PAID"}}</span>
I added a cost class just to make it a little easier to see.
const baseUrl = 'https://www.eventbriteapi.com/v3/events/search/?location.address=45+Depot+Ave.++Bronx%2C+NY+10457&location.within=50mi&token=6RXWSSZPE4APEYSWTJJF';
new Vue({
el: '#app',
data() {
return {
info: null,
isFree: false
}
},
mounted() {
axios
.get(baseUrl)
.then(response => {
this.info = response.data.events;
this.isFree = response.data.events
})
}
})
.cost {
color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<div id="app" class="container">
<h1 id="header" class="title is-1 has-text-centered">Event Lookup for ECH</h1>
<div v-for="event in info">
<!-- Using v-if/else -->
<h2 class="title is-4" id="eventName">{{ event.name.html }}
<span v-if="event.is_free" class="cost tag is-success">FREE</span>
<span v-else class="cost tag is-success">PAID</span>
</h2>
<!-- Using ternary -->
<h2 class="title is-4" id="eventName">{{ event.name.html }}
<span class="cost tag is-success">{{event.is_free ? "FREE" : "PAID"}}</span>
</h2>
<!--<div id="eventDescription">{{ event.description.text }}</div>-->
<div id="eventDateTime">{{ event.start.local }} - {{ event.end.local }}</div>
</div>
</div>
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.