I have to use keypu.enter in a custom input component on Vue. I want that the component <input /> can execute a function hosted in parent component after a enter key event during typing
This is the component code
<input v-on:keyup.enter="$emit('keyup')"/>
And there are the main page
<template>
<se-input #keyup="function()"/>
</template>
<script>
import inputField from '../components/inputfield.vue'
export default {
name: 'inputField',
components: {
'custom-input': inputField
},
},
methods: {
function () {
// Function
}
}
}
</script>
Try to pass value to your custom event, and in parent component listen to that event :
Vue.component('seInput', {
template: `
<div class="">
<input v-on:keyup.enter="$emit('keyup', $event.target.value)"/>
</div>
`
})
new Vue({
el: '#demo',
data() {
return {
inputValue: null
}
},
methods: {
handleInput(val) {
this.inputValue = val
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<h3>{{ inputValue }}</h3>
<se-input #keyup="handleInput"/>
</div>
Related
I want to show or hide the item by clicking the button or clicking the item itself, for example:
<template>
<div>
<button #click="show?show = false:show = true">
{{show?"Hide":"Show"}}
</button>
<div #click="show?show = false:show = true" v-if="show">
Vue Js - click here to Hide
</div>
</div>
</template>
<script>
export default {
data() {
return {
show: null,
};
}
};
</script>
but i want to import the item from another component, so i do this:
the parent component:
<template>
<div>
<button #click="show?show = false:show = true">
{{show?"Hide":"Show"}}
</button>
<item :show="show" />
</div>
</template>
<script>
import item from "item.vue"
export default {
components: {
item
},
data() {
return {
show: null,
};
}
};
</script>
the child component:
<template>
<div #click="show?show = false:show = true" v-if="show">
Vue Js - click here to Hide
</div>
</template>
<script>
export default {
props: {
show: Boolean,
}
};
</script>
but of course, it doesn't work well.
When i click on the item it disappears but the show value in the parent component doesn't change and I get an error saying Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "show".
so how to edit the data value of the parent component from the child component?
(I use Vue 2.6.14)
The solution is to use event emitting (Youtube Tutorial) to send updated data up to the parent component from the child component.
so the code becomes like this:
the parent component:
<template>
<div>
<button #click="show?show = false:show = true">
{{show?"Hide":"Show"}}
</button>
<item :show="show" #state="update($event)" />
</div>
</template>
<script>
import item from "item.vue"
export default {
components: {
item
},
data() {
return {
show: null,
};
},
methods: {
update(value) {
this.show = value;
}
}
};
</script>
the child component:
<template>
<div #click="action" v-if="show">
Vue Js - click here to Hide
</div>
</template>
<script>
export default {
props: {
show: Boolean,
},
methods: {
state() {
if (this.show) {
return false;
} else {
return true;
}
},
action() {
this.$emit("state", this.state())
}
}
};
</script>
Thank you #D.Schaller for helping
I am learning $emit in Vue JS, I decided to create a value called counter in the child component then increment by one when the button is clicked, but I decided to write all the logic in the parent component using $emit
But every time I click on the button, the value does not increase although the method works
LifeCycles.vue
<template>
<div>
<p>{{counter}}</p>
<button #click="add">Click me</button>
</div>
</template>
<script>
export default {
data() {
return {
counter: 0,
};
},
methods: {
add() {
this.$emit('updated', this.counter)
}
},
};
</script>
HeadlineLifeCycle.vue
<template>
<div>
<LifeCycles #updated="usefulMethod" />
</div>
</template>
<script>
import LifeCycles from "./LifeCycles.vue";
export default {
components: {
LifeCycles,
},
methods: {
usefulMethod: function(counter) {
console.log(counter++)
}
}
};
</script>
This is because you're not incrementing count in the child component where it's placed in its data:
const lifecycles = Vue.component('lifecycles', {
template: "#lifecycles",
data() { return { counter: 0 } },
methods: {
add() { this.$emit('updated', ++this.counter); } // fix
}
});
new Vue({
el: "#headlinelifecycle",
components: { lifecycles },
methods: {
usefulMethod: function(counter) { console.log(counter); }
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template id="lifecycles">
<div>
<p>{{counter}}</p>
<button #click="add">Click me</button>
</div>
</template>
<div id="headlinelifecycle"><LifeCycles #updated="usefulMethod" /></div>
If you want to control LifeCycles from the parent state:
const lifecycles = Vue.component('lifecycles', {
template: "#lifecycles",
props: ['counter'],
methods: {
add() { this.$emit('updated', this.counter+1); }
}
});
new Vue({
el: "#headlinelifecycle",
components: { lifecycles },
data() { return { counter: 0 } },
methods: {
usefulMethod: function(counter) {
this.counter = counter;
console.log(this.counter);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template id="lifecycles">
<div>
<p>{{counter}}</p>
<button #click="add">Click me</button>
</div>
</template>
<div id="headlinelifecycle">
<LifeCycles #updated="usefulMethod" :counter="counter" />
</div>
The line
this.$emit('updated', this.counter)
is not emitting this.counter reference, so any time you click on the button, you actually are emmiting the counter initial value which is 0.
So, if you really need to do all the logic in the parent component, you have to define the counter variable in parent component:
lifecycle.vue
<template>
<div>
<p>{{counter}}</p>
<button #click="$emit('clicked')">Click me</button>
</div>
</template>
HeadlineLifeCycle.vue
<template>
<div>
<LifeCycles #clicked="increase" />
</div>
</template>
<script>
import LifeCycles from "./LifeCycles.vue";
export default {
components: {
LifeCycles,
},
data() {
return {
counter: 0,
};
},
methods: {
increase: function() {
console.log(this.counter++)
}
}
};
</script>
You also can pass a variable to the lifecycle.vue as model and manage its value in lifecycle component.
I know use $emit to pass data from child to parent components on VueJS but I want get that value on javascript function. My scenario is:
Parent
created () {
this.$on('getValue', function (params) {
console.log('PARAMS: ' + params)
})
},
Child
methods: {
checkBoxChanged (index) {
this.$emit('getValue', 'some value')
},
}
But it ins't works. Using html I can set on Parent using something like: (I'VE REASONS TO CAN'T DO IT!)
<template>
<div>
<h1>{{ message }}</h1>
<child v-on:listenerChild="listenerChild"/>
</div>
</template>
But I need do this using just javascript.
That's how you can pass data from child to parent:
Vue.component('child-component', {
template:
`<button type="button" #click="emitClick">
Click to emit event to parent component
</button>`,
methods: {
emitClick() {
this.$emit('buttonClicked', 'Magic from child component!');
},
},
});
Vue.component('parent-component', {
template:
`<div>
<div>Child data is: {{ childData }}</div>
<child-component #buttonClicked="handleClick" />
</div>`,
data() {
return {
childData: 'empty',
};
},
methods: {
handleClick(data) {
this.childData = data;
},
},
});
new Vue({
el: '#app',
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<parent-component />
</div>
I have some components that look like this.
<template>
<q-layout>
<v-input v-model="something" />
</q-layout>
</template>
<script>
import { QLayout } from 'quasar'
import { Input } from 'vedana'
export default {
name: 'index',
components: {
QLayout,
Input
},
data () {
return {
something: ''
}
}
}
this v-input component looks like this:
<template>
<input
:type="type ? type : 'text'"
class="v-input"/>
</template>
<script>
export default {
props: ['type'],
name: 'v-input'
}
</script>
When I enter data into the input something does not bind to whatever is in the value of the input that is inside of v-input.
How do I achieve this?
To enable the use of v-model the inner component must take a value property.
Bind the value to the inner <input> using :value, not v-model (this would mutate the prop coming from the parent). And when the inner <input> is edited, emit an input event for the parent, to update its value (input event will update the variable the parent has on v-model).
Also, if you have a default value for the type prop, declare it in props, not in the template.
Here's how your code should be
<template>
<input
:type="type"
:value="value"
#input="$emit('input', $event.target.value)"
class="v-input" />
</template>
<script>
export default {
props: {
type: {default() { return 'text'; }},
value: {} // you can also add more restrictions here
},
name: 'v-input'
}
</script>
Info about what props can have: Components / Passing data With Props.
Demo below.
Vue.component('v-input', {
template: '#v-input-template',
props: {
type: {default() { return 'text'; }},
value: {} // you can also add more restrictions here
},
name: 'v-input'
});
new Vue({
el: '#app',
data: {
something: "I'm something"
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<p>Parent something: {{ something }}</p>
<hr>
Child: <v-input v-model="something" />
</div>
<template id="v-input-template">
<input
:type="type"
:value="value"
#input="$emit('input', $event.target.value)"
class="v-input" />
</template>
https://v2.vuejs.org/v2/guide/components.html#sync-Modifier
<template>
<q-layout>
<v-input :value.sync="something" />
</q-layout>
</template>
<template>
<input
:type="type ? type : 'text'"
v-model="inputVal"
class="v-input"/>
</template>
<script>
export default {
props: ['type', 'value'],
name: 'v-input',
data:function(){
return {
inputVal: ''
};
},
watch:{
value: function(newValue){
this.$emit('update:value', newValue)
}
}
}
</script>
You need to pass your value to the input component using the .sync modifier so the changes will sync back to the parent.
I have a simple root App which includes two different components Room and Machine. And each of these components include one component Datatable which is totally same for both of them. To switch between Room and Machine I'm using dynamic components mechanism, nothing special. When component is changing then I just emit event and component Datatable should log it in console with current module name. The problem is that each time I change component, event is sent multi times. If I understand right, after changing component the old one should be destroyed and the new one created so why this is happening? I'm using Vue.js v.2.4.1
Here is screenshot from console when I switch between components:
Here are components:
App.vue:
<template>
<div id="app">
<select style="padding: 10px" v-model="currentModule" #change="changeComponent">
<option value="Room">Room</option>
<option value="Machine">Machine</option>
</select>
<component :is="currentModule"></component>
</div>
</template>
<script>
import Room from './Room.vue';
import Machine from './Machine.vue';
export default {
name: 'app',
components: {
Room,
Machine
},
data () {
return {
currentModule: 'Room'
}
},
methods: {
changeComponent: function() {
Event.$emit('moduleHasChanged', this.currentModule)
}
},
}
</script>
Machine.vue:
<template>
<div>
Machine template
<datatable></datatable>
</div>
</template>
<script>
import Datatable from './Datatable.vue';
export default {
components: {
Datatable
}
}
</script>
Room.vue:
<template>
<div>
Room template
<datatable></datatable>
</div>
</template>
<script>
import Datatable from './Datatable.vue';
export default {
components: {
Datatable
}
}
</script>
Datatable.vue
<template>
<div>
Datatable
</div>
</template>
<script>
export default {
created() {
Event.$on('moduleHasChanged', (currentModule) => {
console.log(currentModule);
})
}
}
</script>
This is happening because you are continually adding event listeners (when the Datatable component is created) and never removing them. Vue typically handles this for you, but since you are using an event bus you need to do it yourself.
Simply add a beforeDestroy handler and remove the event handler.
console.clear()
const Event = new Vue()
const Datatable = {
template: `
<div>
Datatable
</div>
`,
methods: {
moduleChanged(currentModule) {
console.log(currentModule);
}
},
created() {
Event.$on('moduleHasChanged', this.moduleChanged)
},
beforeDestroy() {
Event.$off('moduleHasChanged', this.moduleChanged)
}
}
const Room = {
template: `
<div>
Room template
<datatable></datatable>
</div>
`,
components: {
Datatable
}
}
const Machine = {
template: `
<div>
Machine template
<datatable></datatable>
</div>
`,
components: {
Datatable
}
}
const App = {
name: 'app',
template: `
<div id="app">
<select style="padding: 10px" v-model="currentModule" #change="changeComponent">
<option value="Room">Room</option>
<option value="Machine">Machine</option>
</select>
<component :is="currentModule"></component>
</div>
`,
components: {
Room,
Machine
},
data() {
return {
currentModule: 'Room'
}
},
methods: {
changeComponent: function() {
Event.$emit('moduleHasChanged', this.currentModule)
}
},
}
new Vue({
el: "#app",
render: h => h(App)
})
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<div id="app">
</div>