Unable to show updated v-model value in input - vue.js

I have the following code:
const BasicInput = {
template: '<input v-model="content" #input="handleInput" />',
prop: ["value"],
data() {
return {
content: this.value
};
},
methods: {
handleInput(e) {
this.$emit("input", this.content);
}
}
};
new Vue({
el: "#app",
data: { name: "" },
mounted() {
self = this;
setTimeout(() => {
self.name = "test";
}, 2000);
},
components: { BasicInput }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<basic-input v-model="name"></basic-input>
<p>
<strong>Name:</strong> {{ name }}
</p>
</div>
How do I get the updated v-model value to also show in the input tag ?

You need to v-bind the property for the BasicInput component. The short form of it is :.
See <basic-input :value="name"></basic-input> usage below, only changed it.
const BasicInput = {
template: '<input v-model="content" #input="handleInput" />',
prop: ["value"],
data() {
return {
content: this.value
};
},
methods: {
handleInput(e) {
this.$emit("input", this.content);
}
}
};
new Vue({
el: "#app",
data: { name: "" },
mounted() {
self = this;
setTimeout(() => {
self.name = "test";
}, 2000);
},
components: { BasicInput }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<basic-input :value="name"></basic-input>
<p>
<strong>Name:</strong> {{ name }}
</p>
</div>

Related

Handle interaction between vue fields

I have prepared a functional code example in JSFiddle of VUE field interaction.
https://jsfiddle.net/JLLMNCHR/2a9ex5zu/6/
I have a custom autocomplete component that works properly, a normal input field, and a 'Load' button which objetive is to load the value entered in the normal input in the autocomplete field.
This 'load' button is not working.
HTML:
<div id="app">
<p>Selected: {{test1}}</p>
<br>
<div>
<label>Test1:</label>
<keep-alive>
<autocomplete v-model="test1" v-bind:key="1" :items="theItems">
</autocomplete>
</keep-alive>
</div>
<br>
<label>Display this in 'test1':</label>
<input type="text" v-model=anotherField>
<button type="button" v-on:click="loadField()">Load</button>
<br>
<br>
<button type="button" v-on:click="displayVals()">Display vals</button>
</div>
<script type="text/x-template" id="autocomplete">
<div class="autocomplete">
<input type="text" #input="onChange" v-model="search"
#keyup.down="onArrowDown" #keyup.up="onArrowUp" #keyup.enter="onEnter" />
<ul id="autocomplete-results" v-show="isOpen" class="autocomplete-results">
<li class="loading" v-if="isLoading">
Loading results...
</li>
<li v-else v-for="(result, i) in results" :key="i" #click="setResult(result)"
class="autocomplete-result" :class="{'is-active':i === arrowCounter}">
{{ result }}
</li>
</ul>
</div>
</script>
VUE.JS:
const Autocomplete = {
name: "autocomplete",
template: "#autocomplete",
props: {
items: {
type: Array,
required: false,
default: () => []
},
isAsync: {
type: Boolean,
required: false,
default: false
}
},
data() {
return {
isOpen: false,
results: [],
search: "",
isLoading: false,
arrowCounter: 0
};
},
methods: {
onChange() {
// Let's warn the parent that a change was made
this.$emit("input", this.search);
// Is the data given by an outside ajax request?
if (this.isAsync) {
this.isLoading = true;
} else {
// Let's search our flat array
this.filterResults();
this.isOpen = true;
}
},
filterResults() {
// first uncapitalize all the things
this.results = this.items.filter(item => {
return item.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
});
},
setResult(result) {
this.search = result;
this.$emit("input", this.search);
this.isOpen = false;
},
onArrowDown(evt) {
if (this.arrowCounter < this.results.length) {
this.arrowCounter = this.arrowCounter + 1;
}
},
onArrowUp() {
if (this.arrowCounter > 0) {
this.arrowCounter = this.arrowCounter - 1;
}
},
onEnter() {
this.search = this.results[this.arrowCounter];
this.isOpen = false;
this.arrowCounter = -1;
},
handleClickOutside(evt) {
if (!this.$el.contains(evt.target)) {
this.isOpen = false;
this.arrowCounter = -1;
}
}
},
watch: {
items: function(val, oldValue) {
// actually compare them
if (val.length !== oldValue.length) {
this.results = val;
this.isLoading = false;
}
}
},
mounted() {
document.addEventListener("click", this.handleClickOutside);
},
destroyed() {
document.removeEventListener("click", this.handleClickOutside);
}
};
new Vue({
el: "#app",
name: "app",
components: {
autocomplete: Autocomplete
},
methods: {
displayVals() {
alert("test1=" + this.test1);
},
loadField() {
this.test1=this.anotherField;
}
},
data: {
test1: '',
anotherField: '',
theItems: [ 'Apple', 'Banana', 'Orange', 'Mango', 'Pear', 'Peach', 'Grape', 'Tangerine', 'Pineapple']
}
});
Any help will be appreciated.
See this new fiddle where it is fixed.
When you use v-model on a custom component you need to add a property named value and watch it for changes, so it can update the local property this.search.

Get object keyname vuejs

I have a data with object, when im using v-for:
data: {
comp: {
title: {
...
},
title2: {
...
},
title3: {
...
},
}
..
div(v-for="item in comp" #click="method(item)")
How i can get name of item (title, title2, title3) in method?
Try this:
new Vue({
el:'#app',
data: {
comp: {
title: {},
title2: {},
title3: {},
}
},
methods: {
itemClicked(item) {
console.log(item);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(val,key) in comp" #click="itemClicked(key)">
{{ key }} - {{ val }}
</div>
</div>

Set focus on input element with Vue

I try to code an inline edit element. I like to have the focus on the input, after click. Here my code:
<span v-show="!name.edit" #click="toggleEdit(this, name)">{{name.val}}</span>
<input type="text"
v-model="name.val"
v-show="name.edit"
v-on:blur=" saveEdit(this, name)"
>
</div>
data: function () {
return {
name: {
val: '',
edit: false
},
}
},
methods: {
...mapMutations([
]),
toggleEdit: function(ev, obj){
obj.edit = !obj.edit;
console.log(obj)
if(obj.edit){
Vue.nextTick(function() {
ev.$$.input.focus();
})
}
},
saveEdit: function(ev, obj){
//save your changes
this.toggleEdit(ev, obj);
}
},
But it's still not working.
Try puting $ref in that specific input and vue.nextTick should be this.$nextTick:
like this:
<input type="text"
ref="inputVal"
v-model="name.val"
v-show="name.edit"
v-on:blur=" saveEdit(this, name)"
>
this.$nextTick(function() {
this.$refs.inputVal.focus();
});
https://codesandbox.io/s/keen-sutherland-euc3c
Usually for dynamic elements i would do this:
<template>
<div>
<template v-for="name in names">
<span :key="name.name" v-show="!name.edit" #click="toggleEdit(this, name)">{{name.val}}</span>
<input
:key="name.name"
type="text"
:ref="name.val"
v-model="name.val"
v-show="name.edit"
v-on:blur=" saveEdit(this, name)"
>
</template>
</div>
</template>
<script>
export default {
name: "App",
components: {},
data: function() {
return {
names: [
{
val: "TEST1",
edit: true
},
{
val: "TEST2",
edit: true
},
{
val: "TEST3",
edit: true
}
]
};
},
methods: {
toggleEdit: function(ev, obj) {
obj.edit = !obj.edit;
console.log(obj);
if (obj.edit) {
this.$nextTick(function() {
this.$refs[`${obj.val}`][0].focus();
});
}
},
saveEdit: function(ev, obj) {
//save your changes
this.toggleEdit(ev, obj);
}
}
};
</script>

Why my Vue Component do not return a value?

I am new with Vue and I wanted to create a component wrapping the kendoComboBox and wanted to use the v-model on it, but it doesn't return an item selected. What is lacking on my code?
This is my Vue Component and the html.
Vue.component('leave-type-2',
{
template: '<input v-bind:value="value" v-on:select="$emit("select", $event.target.dataItem)" />',
props: ['value'],
mounted: function() {
var self = this;
$(this.$el).kendoComboBox({
dataSource: {
transport: {
read: {
url: "../LeaveTool/LeaveTypes",
dataType: "json"
}
}
},
dataTextField: "Description",
dataValueField: "NumCode",
filter: "contains",
select: function(e) {
var dataItem = this.dataItem(e.item.index());
self.$emit('select', { "NumCode": dataItem.NumCode, "Description": dataItem.Description });
},
change: function() {
}
});
}
});
const v = new Vue({
el: "#app",
data: function () {
return {
leaveType: null
}
}
});
<div id="app">
Leave Type Selected: {{ leaveType }}
<leave-type-2
v-model="leaveType"
v-once style="width: 100%">
</leave-type-2>
</div>

Why is the computed property of this component not reactive:

I have an object like this:
myObject: {
items: [{
title: '140',
isActive: true,
}, {
title: '7',
isActive: false
}, {
title: '10',
isActive: false
}]
}
Which I'm using like this:
<my-component :items="myObject.items"></my-component>
This is how the component looks like:
<template>
<div class="i-panel panel-container d-flex"
<div
v-for="item in prefs.items"
class="panel-item"
#click="onClick(item)">
<!-- some content -->
</div>
</div>
</template>
<script>
export default {
name: 'IPanel',
props: {
items: {
type: Array,
default () {
return []
}
}
},
computed: {
// code
prefs () {
return {
items: this.items
}
}
},
methods: {
onClick (item) {
this.prefs.items.forEach(item => {
if (JSON.stringify(item) === JSON.stringify(clickedItem)) {
item.isActive = true
}
})
}
}
}
</script>
When I click an item (and that item is the same as the clickedItem), it's supposed to become isActive true. It does. But I have to refresh the Vue devtools or re-render the page for the change to take effect.
Why isn't item.isActive = true reactive?
In the code you posted, you are using a clickedItem object that is not defined anywhere. I don't know if this is just in the process of writing your question or if it is your problem.
However, when using clickedItem the right way, it seems to work: https://jsfiddle.net/d5z93ygy/4/
HTML
<div id="app" class="i-panel panel-container d-flex">
<div
v-for="item in prefs.items"
class="panel-item"
#click="onClick(item)">
<!-- some content -->{{ item.isActive ? 'active' : 'inactive' }}
</div>
</div>
JS
new Vue({
el: "#app",
data: {
items: [{
title: '140',
isActive: true,
}, {
title: '7',
isActive: false
}, {
title: '10',
isActive: false
}]
},
computed: {
// code
prefs () {
return {
items: this.items
}
}
},
methods: {
onClick (clickedItem) {
this.prefs.items.forEach(item => {
if (JSON.stringify(item) === JSON.stringify(clickedItem)) {
item.isActive = true
}
})
}
}
})
Change
<div
v-for="item in prefs.items"
class="panel-item"
#click="onClick(item)">
<!-- some content -->
</div>
to
<div
v-for="(item, index) in prefs.items"
class="panel-item"
#click="onClick(index)">
<!-- some content -->
</div>
Then, in your change method, go like this:
onClick (index) {
Vue.set(this.items, index, true);
}
https://v2.vuejs.org/v2/guide/list.html#Object-Change-Detection-Caveats