Is there a way to bind a given data prop in template while looping over array?
<div v-for="(page, pageIndex) in pages" :key="pageIndex">
<img
:src=""
#load="onImageLoaded.bind(this, someDataVar)"
/>
</div>
So if in the meantime (until the image gets loaded) someDataVar will gonna be changed, I still want to output in onImageLoaded the original value of someDataVar at the time the image was added to DOM by the for-loop.
PS: I've tried with IIFE but it didn't worked
define a 'directive'.
try this.
new Vue({
el: '#app',
data () {
return {
pages: [1,2,3],
someDataVar: 'someData'
}
},
mounted () {
setTimeout(() => {
this.someDataVar = 'otherData'
}, 1000)
},
directives: {
'init-val': {
inserted: (el, binding) => {
el.dataset.initVal = binding.value
}
}
},
methods: {
onImageLoaded (event) {
console.log(event.target.dataset)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(page, pageIndex) in pages" :key="pageIndex">
<div
v-init-val="someDataVar"
#click="onImageLoaded"
>click me!</div>
</div>
</div>
Related
Here is my code:
<div class="pop-up-chat">
<div id="div1">
<div class="pop-up-msg regular-text">Hi, How may I help you?</div>
<div class="triangle-down"></div>
</div>
</div>
Here I am targeting the pop-up-chat div and setting 5 seconds delay and hiding the div. What's wrong with it?
export default {
name: 'PopUpMsg',
mounted() {
this.msgShow();
},
methods: {
msgShow() {
const msg = document.getElementsByClassName('pop-up-chat');
setTimeout(() => {
msg.style.visibility = 'hidden';
}, 5000);
},
},
}
Just add new property to data showPopup and set it to true then change it to false within mounted hooks
Using v-show to show or hide the wanted element v-if-vs-v-show
<template>
<div>
<!-- binding style -->
<div :style="{visibility: showPopup ? 'visible' : 'hidden' }"
<!-- or use v-show directive to show | hide element -->
<div v-show="showPopup" class="pop-up-chat">
<div id="div1">
<div class="pop-up-msg regular-text">Hi, How may I help you?</div>
<div class="triangle-down"></div>
</div>
</div>
<!-- The rest of your template -->
</div>
</template>
<script>
export default {
name: 'PopUpMsg',
data() {
return {
showPopup: true,
}
}
mounted() {
this.msgShow();
},
methods: {
msgShow() {
setTimeout(() => {
this.showPopup = false
}, 5000)
},
},
}
</script>
Or you can create custom directive v-visible
<div v-visible="showPopup" />
Vue.directive('visible', function(el, binding) {
el.style.visibility = Boolean(binding.value) ? 'visible' : 'hidden';
});
As you are working with Vue.js, I will suggest you to use v-show directive to show and hide the popup.
Demo:
new Vue({
el: '#app',
data: {
isVisible: true
},
mounted() {
this.poppupShow();
},
methods: {
poppupShow() {
setTimeout(() => {
this.isVisible = false;
}, 5000);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="pop-up-chat" v-show="isVisible">
<div id="div1">
<div class="pop-up-msg regular-text">Hi, How may I help you?</div>
<div class="triangle-down"></div>
</div>
</div>
</div>
It works this way
methods: {
msgShow() {
const msg = document.getElementById('msg');
setTimeout(() => {
msg.style.display = 'block';
setTimeout(() => {
msg.style.display = 'none';
}, 10000);
}, 5000);
},
},
.pop-up-chat {
display : none; //initially
}
I want to hide the below loader-wrapper div after 2 seconds of page load.
<div class="loader-wrapper">
<div class="loader"><div class="loader-inner"></div></div>
</div>
Can someone help me on achieving this ?
You could add a property in the data object and use v-show directive to determine whether the element should be visible or not.
If the boolean is false the element is hidden, if true the element is visible.
Method Created called synchronously after the instance is created.
<template>
<div>
<h1 v-show="elementVisible" class="hideElement"> HELLO </h1>
</div>
</template>
<script>
export default {
data() {
return {
elementVisible: true
}
},
created() {
setTimeout(() => this.elementVisible = false, 2000)
}
}
</script>
<template>
<!-- binding style -->
<div class="loader-wrapper" :style="{visibility: showLoader ? 'visible' : 'hidden' }"
<!-- or use v-show directive to show | hide element -->
<div class="loader-wrapper" v-if="showLoader">
<div class="loader"><div class="loader-inner"></div></div>
</div>
</template>
<script>
data() {
showLoader: true,
},
mounted() {
this.hideLoader()
},
methods: {
hideLoader() {
// using setTimeout to programmatically hide loader
setTimeout(() => {
this.showLoader = false
}, 2000)
}
}
</script>
You can write the logic to hide the loader in mounted() hook. Vue calls the mounted() hook when your component is added to the DOM.
Working Demo :
new Vue({
el: '#app',
data: {
isLoaderVisible: true,
},
mounted() {
setTimeout(() => {
this.isLoaderVisible = false
}, 2000)
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="loader-wrapper" v-if="isLoaderVisible">
<div class="loader">
<div class="loader-inner">
Loading...
</div></div>
</div>
</div>
I have seen a few questions similar to this but all revolve around webpack, which I am not currently using.
I have a Vue template:
var question = Vue.component('question', {
props: {
scenario: { type: Object }
},
beforeMount: function () {
this.retrieveScenario();
},
methods: {
postChoice: function () {
Post("Study", "PostScenarioChoice")
},
retrieveScenario: function () {
Get("ScenariosVue", "GetScenario", 1, this,
(c, data) => { this.scenario = data; },
(c, errors) => { console.log(errors); }
);
}
},
template:
`<div class="visible">
<div class="row justify-content-center">
<div class="col-lg-6">
<a v-on:click="this.postChoice">
<img class="img-fluid" v-bind:src="scenario.scenarioLeftImg" />
</a>
</div>
<div class="col-lg-6">
<a v-on:click="this.postChoice">
<img class="img-fluid" v-bind:src="scenario.scenarioLeftImg" />
</a>
</div>
</div>
</div >`
});
The Ajax retrieval returns an object with the following:
returned
Object {
scenarioId: 1,
description: "Dog vs Bolard",
scenarioLeftImg: "images\\Scenarios\\bolard_dog_Left.png",
scenarioRightImg: "images\\Scenarios\\bolard_dog_Right.png",
participantScenarios: [],
scenarioTypesScenarios: []
}
However, the Html, doesn't add the src tag to the tag and I'm really not sure why because the data's clearly available.
Much Help would be greatly appreciated.
This is happening because Vue's template system doesn't "watch" properties (or nested properties) of an object for changes. If you need to do this, then you can either use the computed property with a watch on the computed property, or you can just create two props instead of the single prop. Here is what I would do to change your code:
var question = Vue.component('question', {
props: {
// Replace this prop with the two below.
// scenario: { type: Object }
scenarioLeftImg: { type: String },
scenarioRightImg: { type: String }
},
beforeMount: function () {
this.retrieveScenario();
},
methods: {
postChoice: function () {
Post("Study", "PostScenarioChoice")
},
retrieveScenario: function () {
Get("ScenariosVue", "GetScenario", 1, this,
(c, data) => { this.scenario = data; },
(c, errors) => { console.log(errors); }
);
}
},
template:
`<div class="visible">
<div class="row justify-content-center">
<div class="col-lg-6">
<a v-on:click="this.postChoice">
<img class="img-fluid" v-bind:src="scenarioLeftImg" />
</a>
</div>
<div class="col-lg-6">
<a v-on:click="this.postChoice">
<img class="img-fluid" v-bind:src="scenarioLeftImg" />
</a>
</div>
</div>
</div >`
});
Your main issue is that due to the limitations of Javascript, Vue cannot detect property additions in Objects.
Change to
retrieveScenario: function () {
Get("ScenariosVue", "GetScenario", 1, this,
(c, data) => { Vue.set(this.data, 'scenarios', data); },
(c, errors) => { console.log(errors); }
);
}
Please be aware that it is considered really bad practice to have components modify their props. Rather mirror those props into your vm's data() function in the created() hook of your component, then modify that. If you need the "modified" props outside of your component, emit an event telling those components props has changed.
Also replace the backslashes in your path by slashes:
scenarioLeftImg: "images\\Scenarios\\bolard_dog_Left.png",
scenarioRightImg: "images\\Scenarios\\bolard_dog_Right.png",
has to be
scenarioLeftImg: "images/Scenarios/bolard_dog_Left.png",
scenarioRightImg: "images/Scenarios/bolard_dog_Right.png",
I am trying to click() a bound checkbox in Vue.js 2. I want to click a particular dynamic checkbox in the mounted() lifecycle event, without jQuery.
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="app">
<div ref='users' v-for="user in users">
<input type='checkbox'
:ref='user.username'
:id='user.id'
:value='user.username' />
<label :for='user.id'>{{ user.name }} [username: {{ user.username }}]</label>
</div>
<div #click="trigger" class="trigger">Click me</div>
</div>
<script>
new Vue({
el: '#app',
data: {
users: ''
},
methods: {
popUsers: function() {
axios.get('https://jsonplaceholder.typicode.com/users').then(res => {
this.users = res.data;
});
},
trigger() {
console.log(this.$refs);
this.$refs.Karianne[0].click();//works
}
},
created: function () {
this.popUsers();
},
mounted: function () {
console.log(this.$refs);
this.$refs.Karianne[0].click(); //doesn't work. i want to "click Karianne" when everything is loaded.
}
})
</script>
Here is my jsfiddle: https://jsfiddle.net/zippyferguson/we8Latcw/21/
this.$refs.Karianne[0].click(); works when you click "Click me", but not in on mounted. Too early?
new Vue({
el: '#app',
data: {
users: ''
},
methods: {
popUsers: function() {
let self = this;
axios.get('https://jsonplaceholder.typicode.com/users').then(res => {
this.users = res.data;
self.$nextTick(function() {
self.$refs.Karianne[0].click() //works
})
});
}
},
created: function () {
this.popUsers();
},
mounted: function () {
let self = this;
self.$nextTick(function() {
self.$refs.Karianne[0].click() //doesn't work
})
}
})
Try doing it like this.
mounted() {
Vue.nextTick(() => {
this.$refs.Karianne[0].click()
})
}
I think that for some reason $refs is still empty at the moment of mounting the vue component. If Vue.nextTick doesn't help, try doing it inside a timeout callback.
mounted() {
setTimeout(() => {
this.$refs.Karianne[0].click()
}, 200)
}
I am using Sortable.js and Vue.js. The goal is to sort items and keep data updated.
It worked well with Vue 1.x, but after update to 2.0 sorting became incorrect. Array still properly updates, but items in DOM are in the wrong places.
new Vue({
el: '#app',
template: '#sort',
data: function() {
return {
items: [
"http://placehold.it/200X300?text=image1",
"http://placehold.it/200X300?text=image2",
"http://placehold.it/200X300?text=image3",
"http://placehold.it/200X300?text=image4"
],
}
},
mounted: function() {
this.$nextTick(function () {
Sortable.create(document.getElementById('sortable'), {
animation: 200,
onUpdate: this.reorder.bind(this),
});
})
},
methods: {
reorder: function(event) {
var oldIndex = event.oldIndex,
newIndex = event.newIndex;
this.items.splice(newIndex, 0, this.items.splice(oldIndex, 1)[0]);
}
}
});
jsFiddle
https://jsfiddle.net/4bvtofdd/4/
Can someone help me?
I had a similar problem today.
Add :key value to make sure Vue rerenders elements in correct order after Sortable changes the items order
<div v-for="item in items" :key="item.id">
<!-- content -->
</div>
https://v2.vuejs.org/v2/guide/list.html#key
As it happens, Sortable keeps track of the order in sortable.toArray(), so it's pretty easy to make a computed that will give you the items in sorted order, while the original item list is unchanged.
new Vue({
el: '#app',
template: '#sort',
data: {
items: [
"http://placehold.it/200X300?text=image1",
"http://placehold.it/200X300?text=image2",
"http://placehold.it/200X300?text=image3",
"http://placehold.it/200X300?text=image4"
],
order: null
},
computed: {
sortedItems: function() {
if (!this.order) {
return this.items;
}
return this.order.map((i) => this.items[i]);
}
},
mounted: function() {
this.$nextTick(() => {
const sortable = Sortable.create(document.getElementById('sortable'), {
animation: 200,
onUpdate: () => { this.order = sortable.toArray(); }
});
})
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/Sortable/1.4.2/Sortable.min.js"></script>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="//unpkg.com/vue#2.0.1/dist/vue.js"></script>
<div id='app'></div>
<template id="sort">
<div class="container">
<div class="row sort-wrap" id="sortable">
<div class="col-xs-6 col-md-3 thumbnail" v-for="(item, index) in items" :data-id="index">
<img v-bind:src="item" alt="" class="img-responsive">
</div>
</div>
<div v-for="item in sortedItems">
{{item}}
</div>
</div>
</template>
Make sure you aren't using a prop, or you won't be able to sort. If you are using a prop, assign the prop data to a data attribute and use the data attribute instead.