VueJs emit('input') firing 2 values - javascript

I have a vue component which has an input so to use v-model I use this
<template>
<div class="input-field">
<input
type="text"
v-model="value"
:id="inputId"
placeholder=""
#input="updateText"
/>
<label :for="inputId">{{ label }}</label>
</div>
</template>
<script>
import { ref } from "#vue/reactivity";
export default {
name: "InputField",
props: {
value: { type: String },
inputId: { type: String },
label: { type: String },
},
setup(props, { emit }) {
const value = ref("");
const updateText = () => {
emit("input", value.value);
};
return {
value,
updateText,
};
},
};
</script>
<style lang="less" scoped>
</style>
So when I console so I used the v-model in the parent component but the value is not changing so I tried to print the #input data .. It returns 2 values.. The value of the input and the ref object
<div class="login-box">
<InputField
v-model="username"
label="Username "
inputId="username"
#input="printUser"
/>
<input type="text" />
<div>{{ username }}</div>
Any help.. Thanks!

In vue 3 v-model on a component is syntactic sugar for
<input-field
:model-value="username"
#update:model-value="username = $event"
></input-field>
so you're input field component should be
<template>
<div class="input-field">
<input
type="text"
:value="modelValue"
:id="inputId"
placeholder=""
#input="updateText"
/>
<label :for="inputId">{{ label }}</label>
</div>
</template>
<script>
import { ref } from "#vue/reactivity";
export default {
name: "InputField",
props: {
...
modelValue: { type: String },
...
},
setup(props, { emit }) {
const updateText = (e) => {
emit("update:modelValue", e.target.value);
};
return {
updateText,
};
},
};
</script>

Related

How to store a value from another component's data?

I have two components, is there a way to store value from another component's data?
Here is Create.vue
<template>
<div id="main">
<Editor />
//some codes here
</div>
</template>
<script>
import Editor from './_Create_Editor.vue'
export default {
components: { Editor },
data: () => ({
text: ''
}),
}
</script>
And here is the _Create_Editor.vue.
<template>
//sample input for demonstration purposes
<input type="text" class="form-control" v-model="text"/>
</template>
The code above returns an error:
Property or method "text" is not defined on the instance but referenced during render
I want everytime I type the data: text from Create.vue has the value of it.
How can I possibly make this? Please help.
You can do this by using $emit.
Create.vue
<template>
<div id="main">
<Editor
#edit={onChangeText}
/>
//some codes here
</div>
</template>
<script>
import Editor from './_Create_Editor.vue'
export default {
components: { Editor },
data: () => ({
text: ''
}),
methods: {
onChangeText: function (value) {
this.text = value
}
}
}
</script>
_Create_Editor.vue
<template>
//sample input for demonstration purposes
<input
type="text"
class="form-control"
#change="onChange"
/>
</template>
<script>
export default {
methods: {
onChange: function (event) {
this.$emit('edit', event.target.value)
}
}
}
</script>

How databind a textarea component text value and update it?

I've been working on VueJS just 1 weeks ago for a project.
I've created two components:
* Account.vue (Parent)
<!--It's just a little part of the code-->
<e-textarea
title="Informations complémentaires"
#input="otherInformation" <!--otherInformation is a string variable which contains the text value-->
:value="otherInformation"></e-textarea>
TextArea.vue (Children Component)
<template>
<div class="form-group">
<label for="e-textarea">{{ title }}</label>
<textarea
id="e-textarea"
class="form-control"
row="3"
:value="value"
v-on="listeners"
>
</textarea>
</div>
</template>
<script>
import { FormGroupInput } from "#/components/NowUiKit";
export default {
name: "e-textarea",
components: {
[FormGroupInput.name]: FormGroupInput
},
props: {
title: String,
value: String
},
computed: {
listeners() {
return {
...this.$listeners,
input: this.updateValue
};
}
},
methods: {
updateValue(value) {
this.$emit("input", value);
}
},
mounted() {
console.log(this.components);
}
};
</script>
<style src="#/assets/styles/css/input.css" />
When I write something in my TextArea Custom component from my Account.vue, my text value does not update and my listener function is not passed. Does I need to have something else?
You can easily do this by v-model:
<textarea
id="e-textarea"
class="form-control"
row="3"
v-model="value"
>
</textarea>
it's equals to:
<textarea
id="e-textarea"
class="form-control"
:value="value"
#input="value = $event.target.value"> </textarea>
Bind the value in your custom textarea and the input event:
CustomTextarea.vue
<template>
<div class="form-group">
<label for="e-textarea">{{ title }}</label>
<textarea
id="e-textarea"
class="form-control"
row="3"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</textarea>
</div>
</template>
<script>
import { FormGroupInput } from "#/components/NowUiKit";
export default {
name: "e-textarea",
components: {
[FormGroupInput.name]: FormGroupInput
},
model: {
prop: "textAreaVue"
},
props: {
title: String,
value: String
},
computed: {
listenerFunction() {
return {
...this.$listener,
input: this.updateValue
};
}
},
methods: {
updateValue(value) {
console.log("function has been passed");
this.$emit("input", value);
}
},
mounted() {
console.log(this.components);
}
};
</script>
<style src="#/assets/styles/css/input.css" />
And use it with v-model :
<custom-textarea
title="Informations complémentaires"
v-model="otherInformation"></custom-textarea>
More explanation here
Hopefully it will save someone some time. In Vue.js 3 they changed this a bit compared the Vue.js 2 and i got it working with this:
<textarea :value="modelValue"
#input="onInput" />
and the onInput method looks like this:
onInput: function (e) {
this.$emit("update:modelValue", e.target.value);
}
of course you have to have the prop 'modelValue' on your 'e-textarea' component instead of value as it was the case in vue 2.
i also added a watcher on this modelValue just in case it fails to update:
props: {
modelValue: {
type: String,
default: null
}
}
watch: {
modelValue: function () {
return this.modelValue;
},
},
and yes, you use the component like so:
<e-textarea v-model="otherInformation" />
of course you can listen to the input event also if you want to, or need to for your specific case
you can also find more about this changes on
here
and here

Pass data to another component

I have a simple form component:
<template>
<div>
<form #submit.prevent="addItem">
<input type="text" v-model="text">
<input type="hidden" v-model="id">
<input type="submit" value="enviar">
</form>
</div>
</template>
This component has a method that use $emit to add text item to a parent data:
addItem () {
const { text } = this
this.$emit('block', text)
},
Here is markup on my main file:
<template>
<div id="app">
<BlockForm #block="addBlock"/>
<Message v-bind:message="message"/>
</div>
</template>
And the script:
export default {
name: 'app',
components: {
BlockForm,
Message
},
data () {
return {
message : []
}
},
methods: {
addBlock (text) {
const { message } = this
const key = message.length
message.push({
name: text,
order: key
})
}
}
}
My question is: Message component list all items create by BlockForm component and stored inside message array. I add a edit button for each item inside Message list. How can I pass item text to be edited in BlockForm component?
You could just bind the input inside the BlockForm to a variable that is in the parent component. This way when you $emit from the child component, just add the value to the messages.
export default {
name: 'app',
components: {
BlockForm,
Message
},
data () {
return {
message : [],
inputVal: {
text: '',
id: ''
}
}
},
methods: {
addBlock () {
const key = this.message.length
this.message.push({
name: this.inputVal.text,
order: this.inputVal.text.length // If the logic is different here, you can just change it
})
this.inputVal = {
text: '',
id: ''
}
}
}
}
Now when you are calling the BlockForm,
<template>
<div id="app">
<BlockForm propVal="inputVal" #block="addBlock"/>
<Message v-bind:message="message"/>
</div>
</template>
and inside BlockForm,
<template>
<div>
<form #submit.prevent="addItem">
<input type="text" v-model="propVal.text">
<input type="hidden" v-model="probVal.id">
<input type="submit" value="enviar">
</form>
</div>
</template>
Now, when you press edit for existing message, simple assign that "Message" to inputVal data property mapping it to proper text and id.

Vue JS - injecting default value to custom radio group

So i tried to inject a default value to custom radio component that i wrote
Here's the code:
<template>
<div class="custom-radio-button">
{{value}}
<div v-for= "item in localValue">
<input type="radio" :value="item.value" name=item.name #click=onSelected(item.value) >
<span>{{item.label}}</span>
</input>
</div>
</div>
<script>
import Vue from 'vue'
const name = 'CustomRadioButton'
export default {
name,
componentName: name,
props: [ 'name', 'value', 'isDefault', 'label'],
data() {
return {
localName: this.name,
localValue: this.value
}
},
methods: {
onSelected (value) {
this.$emit('clicked', value)
}
}
}
</script>
And here's how i called it:
<CustomRadioButton :value=RadioFieldData #clicked="isRadioButtonSelection" isDefault='yellow'></CustomRadioButton>
And here's the Json Data that goes with it
RadioFieldData:[
{label:'Fire', value:'red', name:'colour' },
{label:'Sun', value:'yellow', name:'colour',isDefault:'yellow'},
{label:'Water', value:'blue', name:'colour'}
]
My question is what is the best way to pass the value "yellow" to the radio buttons group?
Your issue is that props need to be represented in their kebab-case format when used in your template. To set isDefault to "yellow", you need to use
is-default="yellow"
See https://v2.vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case
Once you're able to read that property correctly, you can use
:checked="item.value == isDefault"
Here's an example.
Vue.component('custom-radio-button', {
template: `<div class="custom-radio-button">
Default: {{isDefault}}
<div v-for="item in value">
<input type="radio" :value="item.value" name="item.name" #click="onSelected(item.value)" :checked="item.value == isDefault" />
<span>{{item.label}}</span>
</div></div>`,
props: ['value', 'isDefault'],
methods: {
onSelected(value) {
this.$emit('clicked', value)
}
}
})
new Vue({
el: '#app',
methods: {
isRadioButtonSelection (val) {
console.log('isRadioButtonSelection', val)
}
},
data: {
RadioFieldData: [{"label":"Fire","value":"red","name":"colour"},{"label":"Sun","value":"yellow","name":"colour","isDefault":"yellow"},{"label":"Water","value":"blue","name":"colour"}]
}
})
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
<custom-radio-button :value="RadioFieldData"
#clicked="isRadioButtonSelection"
is-default="yellow">
</custom-radio-button>
</div>

Pass multiple parameter by POST axios vue

I am trying to pass a props value and an form value to the backend controller using axios. But it only sends form value not the props value. My code is -
<template>
<form #submit.prevent='onSubmit'>
<div class="media-comment">
<input type="text" v-model='form.comment' class="form-control" placeholder="comment...">
</div>
</form>
</template>
<script>
export default {
props: ['postId'],
data() {
return {
form: new Form({comment: ''}),
id: this.postId
}
},
methods: {
onSubmit() {
console.log(this.postId); // it shows the value in console but the value doesnt pass
this.form
.post('comments', this.data)
.then(post => this.$emit('completed', comment));
}
}
}
</script>
in console it shows only the comment, not the prop value:
How to pass both value ??
thanks in advance
here i got the solution.
<template>
<form #submit.prevent='onSubmit'>
<div class="media-comment">
<input type="text" v-model='comment' class="form-control" placeholder="comment...">
</div>
</form>
</template>
<script>
export default {
props: ['postId'],
data() {
return {
comment: ''
}
},
methods: {
onSubmit() {
axios.post('comments', {comment: this.comment, id: this.postId})
.then(post => this.$emit('completed', comment));
}
}
}
</script>

Categories

Resources