Loop event fired with buefy autocomplete - vue.js

I have 2 autocomplete inputs :
<template>
<b-autocomplete
v-model="code"
:open-on-focus="true"
#input="updateDescription"
/>
<b-autocomplete
v-model="description"
:open-on-focus="true"
#input="updateCode"
/>
</template>
<script>
export default {
data () {
return {
code: '',
description: ''
}
},
methods: {
updateCode (description) {
this.code = // function to find the code corresponding to the right description
},
updateDescription (code) {
this.description = // function to find the description corresponding to the right code
}
}
}
<script>
When, the code input is modified, I would like to update the value of the description input and in the same way, when the description is modified by the user, I would like the code input to be updated.
However, once code is modified, the #input is fired which update description and the fired the #input as well.
How can I only listen for the user event ?

Try with :value instead v-model:
new Vue({
el: '#app',
data () {
return {
code: '',
description: ''
}
},
methods: {
updateCode () {
this.code = 2
},
updateDescription () {
this.description = 3
}
}
})
<link rel="stylesheet" href="https://unpkg.com/buefy/dist/buefy.min.css">
<div id="app">
<b-autocomplete
:value="code"
:open-on-focus="true"
#input="updateDescription"
></b-autocomplete>
<b-autocomplete
:value="description"
:open-on-focus="true"
#input="updateCode"
></b-autocomplete>
</div>
<script src="https://unpkg.com/vue#2"></script>
<script src="https://unpkg.com/buefy/dist/buefy.min.js"></script>

Related

How to display the value of a variable

Gets data from collection:
const pageTitles = {
homePage: 'Main'
...
}
export default pageTitles
If I make all this way:
<div><span>{{pageTitles.homePage}}</span></div>
everything is ok.
But i need to show the value depending on route. I tried to make this:
pageTitle(){
if (this.$route.path === '/'){
return pageTitles.homePage
}
}
and in div I have {{pageTitle}}, but it doesn't work. Why it doesn't work?
you've omitted the this keyword before pageTitles.homePage in your computed property
pageTitle(){
if (this.$route.path === '/'){
return this.pageTitles.homePage
}
}
It should work, Here you go :
new Vue({
el: '#app',
data: {
pageTitles: {
homePage: 'Main'
}
},
computed: {
pageTitle() {
return this.pageTitles.homePage
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>{{ pageTitle }}</h2>
</div>

Why Vue.js #input event isn't fired when button is clicked?

Why Vue.js #input event isn't fired when button is clicked?
When I change count value directly (click on input element and type new value) alert method is fired.
new Vue({
el: "#app",
data: {
count: 0
},
methods: {
add: function() {
this.count += 1;
},
alert: function() {
alert('Count has been changed!');
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model.number="count" #input="alert">
<button #click="add">+1</button>
</div>
You can invoke alert method from inside add method:
add: function() {
this.count += 1;
// invoke alert()
this.alert();
}
I am sure its #change not #input:
<input type="text" v-model.number="count" #change="alert">
Alternatively:
watch : {
number: function (newVal) {
alert();
}
}
#input isn't for any changes to an input tag; it's specifically triggered when a user directly modifies the input tag. You want something like watch:
new Vue({
el: "#app",
data: {
count: 0
},
methods: {
add: function() {
this.count += 1
}
},
watch: {
count: function() {
alert('Count has been changed!')
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model.number="count" />
<button #click="add">+1</button>
</div>

How do I trigger a recalculation in a Vue app?

I'm working on a project with Vue and VueX. In my component, I have a calculated method that looks like this:
...mapState([
'watches',
]),
isWatched() {
console.log('check watch');
if (!this.watches) return false;
console.log('iw', this.watches[this.event.id]);
return this.watches[this.event.id] === true;
},
And in my store, I have the following:
addWatch(state, event) {
console.log('add', state.watches);
state.watches = {
...state.watches,
[event]: true,
};
console.log('add2', state.watches);
},
However, this doesn't trigger a recalculation. What's going on?
Try changing return this.watches[this.event.id] === true;
to
return this.$store.commit("addWatch", this.event.id);
The code you have shown is correct, so the problem must be elsewhere.
I assume by 'calculated method' you mean computed property.
Computed properties do not watch their dependencies deeply, but you are updating the store immutably, so that is not the problem.
Here is a bit of sample code to give you the full picture.
Add event numbers until you hit '2', and the isWatched property becomes true.
Vue.use(Vuex);
const mapState = Vuex.mapState;
const store = new Vuex.Store({
state: {
watches: {}
},
mutations: {
addWatch(state, event) {
state.watches = { ...state.watches, [event]: true };
}
}
});
new Vue({
el: "#app",
store,
data: {
numberInput: 0,
event: { id: 2 }
},
methods: {
addNumber(numberInput) {
this.$store.commit("addWatch", Number(numberInput));
}
},
computed: {
...mapState(["watches"]),
isWatched() {
if (!this.watches) return false;
return this.watches[this.event.id] === true;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.1.0/vuex.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>Watches: {{ watches }}</div>
<div>isWatched: {{ isWatched }}</div>
<br>
<input v-model="numberInput" type="number" />
<button #click="addNumber(numberInput)">
Add new event
</button>
</div>

vue.js – get new data information

I'm building a chrome extension using vue.js. In one of my vue components I get tab informations of the current tab and wanna display this information in my template. This is my code:
<template>
<div>
<p>{{ tab.url }}</p>
</div>
</template>
<script>
export default {
data() {
return {
tab: {},
};
},
created: function() {
chrome.tabs.query({ active: true, windowId: chrome.windows.WINDOW_ID_CURRENT }, function(tabs) {
this.tab = tabs[0];
});
},
};
</script>
The Problem is, that the template gets the data before it's filled through the function. What is the best solution for this problem, when the tab data doesn't change after it is set once.
Do I have to use the watched property, although the data is only changed once?
// EDITED:
I've implemented the solution, but it still doesn't work. Here is my code:
<template>
<div>
<div v-if="tabInfo">
<p>set time limit for:</p>
<p>{{ tabInfo.url }}</p>
</div>
<div v-else> loading... </div>
</div>
</template>
<script>
export default {
data() {
return {
tabInfo: null,
};
},
mounted() {
this.getData();
},
methods: {
getData() {
chrome.tabs.query({ active: true, windowId: chrome.windows.WINDOW_ID_CURRENT }, function(tabs) {
console.log(tabs[0]);
this.tabInfo = tabs[0];
});
},
},
};
</script>
The console.log statement in my getData function writes the correct object in the console. But the template only shows the else case (loading...).
// EDIT EDIT
Found the error: I used 'this' in the callback function to reference my data but the context of this inside the callback function is an other one.
So the solution is to use
let self = this;
before the callback function and reference the data with
self.tab
You could initialize tab to null (instead of {}) and use v-if="tabs" in your template, similar to this:
// template
<template>
<div v-if="tab">
{{ tab.label }}
<p>{{ tab.body }}</p>
</div>
</template>
// script
data() {
return {
tab: null,
}
}
new Vue({
el: '#app',
data() {
return {
tab: null,
}
},
mounted() {
this.getData();
},
methods: {
getData() {
fetch('https://reqres.in/api/users/2?delay=1')
.then(resp => resp.json())
.then(user => this.tab = user.data)
.catch(err => console.error(err));
}
}
})
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<div v-if="tab">
<img :src="tab.avatar" width="200">
<p>{{tab.first_name}} {{tab.last_name}}</p>
</div>
<div v-else>Loading...</div>
</div>

VueJS 2 update contenteditable in component from parent method

I have editable element updated by component method, but i have also json import and i want to update element my parent method. I can update model, but editable element doesn´t bind it. If i insert content to component template, it will bind updated model, but then i can´t really edit it.
Here´s my example: https://jsfiddle.net/kuwf9auc/1/
Vue.component('editable', {
template: '<div contenteditable="true" #input="update"></div>', /* if i insert {{content}} into this div, it wil update, but editing behave weird */
props: ['content'],
mounted: function () {
this.$el.innerText = this.content;
},
methods: {
update: function (event) {
console.log(this.content);
console.log(event.target.innerText);
this.$emit('update', event.target.innerText);
}
}
})
var app = new Vue({
el: '#myapp',
data: {
herobanner: {
headline: 'I can be edited by typing, but not updated with JSON upload.'
}
},
methods: {
uploadJSON: function (event) {
var input = event.target;
input.src = URL.createObjectURL(event.target.files[0]);
var data = input.src;
$.get(data, function(data) {
importdata = $.parseJSON(data);
this.$data.herobanner = importdata.herobanner;
}.bind(this));
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<main id="myapp" class="container-fluid">
<input type="file" id="file" name="file" #change="uploadJSON" style="display: none; width: 1px; height: 1px"/>
<a href="" onclick="document.getElementById('file').click(); return false" title="Import settings from JSON file">
upload JSON
</a>
<h1>
<editable :content="herobanner.headline" #update="herobanner.headline = $event"></editable>
</h1>
Real value of model:
<br>
<h2>{{herobanner.headline}}</h2>
</main>
Working example:
Vue.component('editable', {
template: `
<div contenteditable="true" #blur="emitChange">
{{ content }}
</div>
`,
props: ['content'],
methods: {
emitChange (ev) {
this.$emit('update', ev.target.textContent)
}
}
})
new Vue({
el: '#app',
data: {
herobanner: {
headline: 'Parent is updated on blur event, so click outside this text to update it.'
}
},
methods: {
async loadJson () {
var response = await fetch('https://swapi.co/api/people/1')
var hero = await response.json()
this.herobanner.headline = hero.name
},
updateHeadline (content) {
this.herobanner.headline = content
}
}
})
<main id="app">
<button #click="loadJson">Load JSON data</button>
<h1>
<editable
:content="herobanner.headline"
v-on:update="updateHeadline"
>
</editable>
</h1>
<h2>{{herobanner.headline}}</h2>
</main>
<script src="https://unpkg.com/vue#2.5.3/dist/vue.min.js"></script>