Vuejs v-on:click not working in v-if - vue.js

It is strange. I am trying to trigger a method when an element is clicked in the v-for loop. But it does not work when I use v-if or v-show. This is my HTML code sample;
<div class="chosen-drop custom_choices" v-if="showResults"> <!-- -->
<ul class="chosen-results">
<li class="active-result level-0 isresult" v-for="City in Results" v-bind:class="{ highlighted: SelectCity.name==City.name }" v-on:click="HandleSelectCity(City)" >{{ City.name }}</li>
</ul>
</div>
This is my method;
methods: {
HandleSelectCity: function (City){
this.SelectCity = City;
this.search_input = City.name;
}
},
I am using Vuejs 1.0.8

This works as expected for me.
new Vue({
el: '#app',
data: {
showResults: true,
Results: [{
name: 'one'
},
{
name: 'two'
}
],
SelectCity: null
},
methods: {
HandleSelectCity(City) {
this.SelectCity = City;
this.search_input = City.name;
}
}
});
.highlighted {
background-color: yellow;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.8/vue.min.js"></script>
<div id="app" class="chosen-drop custom_choices" v-if="showResults">
<ul class="chosen-results">
<li class="active-result level-0 isresult" v-for="City in Results" v-bind:class="{ highlighted: SelectCity.name==City.name }" v-on:click="HandleSelectCity(City)">{{ City.name }}</li>
</ul>
</div>

I have solved the problem. This was just a conflict between the v-on:click and v-on:blur When the element that had v-if was removed the user didn't have any time to click on the element with the v-on:click
I solved the problem by adding a delay.

Related

using bootstrap tooltip with Vue v-for

I want to add a bootstrap tooltip in each IMG tag that I create from Vue v-for but once I use v-for the tooltip does not work anymore.
This work without v-for-
<img src="warning.png" width="40px" heigh="40px" data-toggle="tooltip" title="Some tooltip text!">
Once using v-for, it stopped working-
<img v-for="item,idx in EQP_USER_NOW" src="warning.png" width="40px" heigh="40px"
data-toggle="tooltip" title="Some tooltip text!" v-bind:id="idx"></img>
I just found the problem was happened after i modify the Vue data (EQP_USER_NOW in my case)
For example,after click the button below (modify data)
the data changed but the new IMG tag not worked with tootip.
var vm = new Vue({
el: '#vm',
data: {
EQP_USER_NOW: [{
EQP: "A",
USER: "Andy"
},
{
EQP: "B",
USER: "Tony"
}
],
},
methods: {
modify_data() {
var vm = this
vm.EQP_USER_NOW = [{
EQP: "A",
USER: "Andy"
},
{
EQP: "B",
USER: "Tony"
},
{
EQP: "C",
USER: "Max"
}
]
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.6/umd/popper.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.5.3/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script>
$(function() {
$('[data-toggle="tooltip"]').tooltip({
animated: 'fade',
placement: 'right',
html: true
})
})
</script>
<body>
<div id="vm">
<button #Click="modify_data()">modify data</button>
<div class="container-fluid">
<div class="row">
<div class="col-12">
<img v-for="(item, idx) in EQP_USER_NOW" :key="idx" src="https://picsum.photos/200/200" width="100px" heigh="100px" data-toggle="tooltip" title="Some tooltip text!" v-bind:id="idx">
</div>
</div>
</div>
</div>
</body>
Try doing the following small fixes-
IMG is a self-closing tag, do not close it manually.
When using for loop, a key attribute is recommended to be used.
It's best practice to use parenthesis to wrap multiple params like (item, idx).
Finally, replace your code with this-
<img
v-for="(item, idx) in EQP_USER_NOW"
:key="idx"
src="https://picsum.photos/200/300"
width="40px"
heigh="40px"
data-toggle="tooltip"
title="Some tooltip text!"
v-bind:id="idx"
>

How can I add a task to a list in my Vue 2 to-do app?

I am trying to add a task to a tasklist in Vue based on the input and add task button, but I keep getting the error "taskList is not defined". Does anybody see how to fix this problem? The code is as following:
<template>
<div id="input">
<form>
<input v-model="task.name">
<button v-on:click="addTask" v-bind:value="task.name">+</button>
</form>
<ol>
<div v-for="task in taskList" :key="task.id">
{{ task.name }}
<div v-if="task.completed">
<h2> Done </h2>
</div>
<div v-else>
<h2> Not done</h2>
</div>
</div>
</ol>
</div>
</template>
<script>
export default {
name: 'AddTask',
data: function() {
return {
taskList: [
{
name: 'task', completed: false, id: 3
}
] }
},
methods: {
addTask: function (task) {
taskList.push(task);
alert('test');
}
}
}
</script>
Ps. any other Vue tips are welcome as well.
You need to separate out your taskList and the current task you're adding, decouple it as a new object, then add it to your taskList array.
When referring to items in your data object you need to use the this keyword – e.g this.taskList rather than taskList:
new Vue({
el: "#app",
data: {
id:1,
taskList: [],
currentTask:{
completed:false,
name:'',
id:this.id
}
},
methods: {
addTask: function() {
let newTask = {
completed:this.currentTask.completed,
name:this.currentTask.name,
id:this.currentTask.id
}
this.taskList.push(newTask);
this.id++;
//alert('test');
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="input">
<ol>
<li v-for="task in taskList" :key="task.id">
{{ task.name }}
<input type="checkbox"
:checked="task.completed"
#change="task.completed = !task.completed">
<span v-if="task.completed">
Done
</span>
<span v-else>
Not Done
</span>
</li>
</ol>
<input type="text" v-model="currentTask.name">
<button v-on:click="addTask">+</button>
</div>
</div>
From what I see in your template you use tasklist but you define it as taskList You will want to make sure your names are in the same case. Usually you'll see camelCase in vue, but other popular ones are snake_case and PascalCase

Vue.js bind style (class) of each item in list with v-for dependent on item data

I have a vue object with an array of items as data (in my case flightplans).
The list is rendered correctly so far.
Now comes the problem. I want to apply different styles while iterating with v-for to each item (flightplan) in the list dependent of the value of current iterated flightplan memeber fplType.
Currently all list items (flightplans) get the class flightplan-list-ifr-dep.
But i need something like (pseudo code):
<li v-for="flightplan in flightplans"
v-bind:id="flightplan.id"
v-bind:class="{
flightplan-list-ifr-dep: flightplan.fplType === 'departure',
flightplan-list-ifr-arr: flightplan.fplType === 'arrival'
}"
>
So each items gets its own class applied dependent from the fplType of the current iterated flightplan.
<div id="flightplan-list-area" class="flightplan-list-area-style">
<ul>
<li v-for="flightplan in flightplans"
v-bind:id="flightplan.id"
#click="selected(flightplan, $event)">
<div class="flightplan-list-ifr-dep">
<p class="flightplan-list-ifr-dep-callsign">{{ flightplan.callsign }}</p>
<p class="flightplan-list-ifr-dep-aircraft-type">{{ flightplan.aircraft_type }}</p>
<p class="flightplan-list-ifr-dep-aircraft-wtc">{{ flightplan.aircraft_wtc }}</p>
</div>
</li>
</ul>
</div>
<script lang="javascript">
var vue_FLIGHTPLAN_MODEL = new Vue({
el: "#flightplan-list-area",
data: {
flightplans: [],
selected_flightplan_element: null,
},
});
</script>
Your syntax is almost right, but since your class names contain the "-" character, you just need to quote them inside v-bind:class:
...
v-bind:class="{
'flightplan-list-ifr-dep': flightplan.fplType === 'departure',
'flightplan-list-ifr-arr': flightplan.fplType === 'arrival'
}"
...
Live demo
var vue_FLIGHTPLAN_MODEL = new Vue({
el: "#flightplan-list-area",
data: {
flightplans: [
{ id: 1, callsign: 'ABC', aircraft_type: 'Boeing 737', aircraft_wtc: 'xyz', fplType: 'departure' },
{ id: 2, callsign: 'DEF', aircraft_type: 'Boeing 737', aircraft_wtc: 'uvw', fplType: 'arrival' },
{ id: 3, callsign: 'HIJ', aircraft_type: 'Boeing 737', aircraft_wtc: 'abc', fplType: 'departure' },
],
selected_flightplan_element: null,
},
methods: {
selected (plan, e) {
this.selected_flightplan_element = plan;
}
},
});
li.flightplan-list-ifr-dep {
color: blue;
}
li.flightplan-list-ifr-arr {
color: green;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="flightplan-list-area" class="flightplan-list-area-style">
<ul>
<li v-for="flightplan in flightplans"
v-bind:id="flightplan.id"
v-bind:class="{
'flightplan-list-ifr-dep': flightplan.fplType === 'departure',
'flightplan-list-ifr-arr': flightplan.fplType === 'arrival'
}"
#click="selected(flightplan, $event)">
<div class="flightplan-list-ifr-dep">
<p class="flightplan-list-ifr-dep-callsign">{{ flightplan.callsign }}</p>
<p class="flightplan-list-ifr-dep-aircraft-type">{{ flightplan.aircraft_type }}</p>
<p class="flightplan-list-ifr-dep-aircraft-wtc">{{ flightplan.aircraft_wtc }}</p>
</div>
</li>
</ul>
</div>
You can either use the object style syntax like so:
<li v-for="flightplan in flightplans">
<div :class="{
'fpl-foo': flightplan.fplType === 1,
'fpl-bar': flightplan.fplType === 2,
'fpl-baz': flightplan.fplType === 3
}">
<!-- ... -->
</div>
</li>
...or use a method:
<li v-for="flightplan in flightplans">
<div :class="getClass(flightplan.fplType)">
<!-- ... -->
</div>
</li>
methods: {
getClass (fplType) {
// Determine the class and return it,
// this can also be an array in case
// of more than one class
}
}
Your pseudocode is right.You can bind a class dynamically.See class and style Bindings
So the follow code will work for you:
<li v-for="flightplan in flightplans"
:key="flightplan.id"
v-bind:id="flightplan.id"
v-bind:class="{
'flightplan-list-ifr-dep': flightplan.fplType === 'departure',
'flightplan-list-ifr-arr': flightplan.fplType === 'arrival'
}"
>
And when using v-for,it is recommended always to use a unique key.
I made a simplify example for you.See it in action

Can't get a reset button to clear out a checkbox

I'm using Vue.js v2 and I've defined a single-file component, RegionFacet.vue. It lists some regions that relate to polygons on a map (click a value, the corresponding polygon appears on the map).
Separately, I have a reset button. When that gets clicked, I call a method in RegionFacet to unselect any checkboxes displayed by RegionFacet. The model does get updated, however, the checkboxes remain checked. What am I missing?
<template>
<div class="facet">
<div class="">
<div class="panel-group" id="accordion">
<div class="panel panel-default">
<div class="panel-heading">
<a data-toggle="collapse"v-bind:href="'#facet-' + this.id"><h4 class="panel-title">Regions</h4></a>
</div>
<div v-bind:id="'facet-' + id" class="panel-collapse collapse in">
<ul class="list-group">
<li v-for="feature in content.features" class="list-group-item">
<label>
<input type="checkbox" class="rChecker"
v-on:click="selectRegion"
v-bind:value="feature.properties.name"
v-model="selected"
/>
<span>{{feature.properties.name}}</span>
</label>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['content'],
data: function() {
return {
id: -1,
selected: []
}
},
methods: {
selectRegion: function(event) {
console.log('click: ' + event.target.checked);
if (event.target.checked) {
this.selected.push(event.target.value);
} else {
var index = this.selected.indexOf(event.target.value);
this.selected.splice(index, 1);
}
this.$emit('selection', event.target.value, event.target.checked);
},
reset: function() {
this.selected.length = 0;
}
},
created: function() {
this.id = this._uid
}
}
</script>
<style>
</style>
You are directly setting the array length to be zero, which cannot be detected by Vue, as explained here: https://v2.vuejs.org/v2/guide/list.html#Caveats
Some more info: https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
To overcome this, you may instead set the value of this.selected as follows:
reset: function() {
this.selected = [];
}

v-on:click not working in a child component

First thing first I'm new to vue.js.
what I'm trying to do when the user click on the expander anchor tag in the item-preview component the item-details will display and the item-preview will be hide. Now the problem occurs when the item-preview displayed and i'm trying to toggle it by clicking its own expander anchor tag. I do not whats wrong with this.
Here is my HTML templates.
<script type="text/x-template" id="grid">
<div class="model item" v-for="entry in data">
<item-preview v-bind:entry="entry" v-if="entry.hide == 0">
</item-preview>
<item-details v-bind:entry="entry" v-if="entry.hide == 1">
</item-details>
</div>
</script>
<script type="text/x-template" id="item-preview">
<header class="preview">
<a class="expander" tabindex="-1" v-on:click="toggle(entry)"></a>
<span class="name rds_markup">
{{ entry.name }}
</span>
</header>
</script>
<script type="text/x-template" id="item-details">
<div class="edit details">
<section class="edit" tabindex="-1">
<form action="#">
<fieldset class="item name">
<a class="expander" v-on:click="toggle(entry)"></a>
{{ entry.name }}
</fieldset>
</form>
</section>
</div>
</script>
And here how I called the grid component on my view.
<grid
:data="packages">
</grid>
And for my Vue implementation
var itemPreview = Vue.component('item-preview',{
'template':"#item-preview",
'props':{
entry:Object
},
methods:{
toggle:function(entry){
entry.hide = !!entry.hide;
return true;
}
}
});
var itemDetails = Vue.component('item-details',{
'template':"#item-details",
'props':{
entry:Object
},
methods:{
toggle:function(entry){
entry.hide = !!entry.hide;
return true;
}
}
});
var grid = Vue.component('grid',{
'template':"#grid",
'props':{
data:Array,
},
components:{
'item-preview': itemPreview,
'item-details': itemDetails
},
methods:{
toggle:function(entry){
entry.hide = !!entry.hide;
return true;
}
}
});
var vm = new Vue({
el:'#app',
data:{
message:'Hello',
packages:{}
},
ready:function(){
this.fetchPackages();
},
methods:{
fetchPackages:function(){
this.$http.get(url1,function( response ){
this.$set('packages',response);
});
},
}
});
Silly me. It took me 30minutes to figure out what is wrong with this code.
What I did to fix this is instead of entry.hide = !!entry.hide; I use entry.hide = true in item-preview component and in the item-details entry.hide = false. this fix my issue.