I did a custom input component, it works correctly but there is a problem: when i try to update its value from a method the model is updated but the input value still there.
This is my component:
https://codepen.io/ken-ramirez/pen/JgyKad
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: '' },
components: { BasicInput },
methods: {
restart() {
this.name = ''
}
}
})
You can press on restart button to see what i mean.
You have a mistake in your code: props, not prop.
But this is not enough, also you need to update your content manually, it's not reactive with value prop. Everything declared inside data is not reactive with its initial values.
const BasicInput = {
template: '<input v-model="content" #input="handleInput" />',
props: ['value'],
data () {
return {
content: this.value
}
},
methods: {
handleInput (e) {
this.$emit('input', this.content)
}
},
watch: {
value(val) {
this.content = val;
}
}
}
Like #NikitaK mentioned in his answer you're making a typo , you should write props instead of prop, but i want to give a shorter solution without using watcher property only with this code #input="$emit('input',$event.target.value)"
Full example
const BasicInput = {
template: `<input :value="value" #input="$emit('input',$event.target.value)" />`,
props: ['value']
}
new Vue({
el: '#app',
data() {
return{
name: ''
}},
components: { BasicInput },
methods: {
restart() {
this.name = ''
}
}
})
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<basic-input v-model="name"></basic-input>
<p>
<strong>Name:</strong> {{ name }}
</p>
<button #click="restart">restart</button>
</div>
Related
I am trying to change the data depending on the value of my props in a Nuxtjs app.
export default {
props: {
moved: {
default: false,
type: Boolean,
}
},
data: function () {
if (!this.moved){
dataName: {
fill: "value1"
}
else dataName: {
fill: "value2"
}
return dataName
}
}
}
But I have an error message telling me that dataName is not defined. I don't know what I am doing wrong here...
You can make computed property instead:
Vue.component('Child', {
template: `
<div>
{{ dataName }}
<svg height="210" width="500">
<polygon points="100,10 40,198 190,78 10,78 160,198" :fill="dataName.fill"/>
</svg>
</div>
`,
props: {
moved: {
default: false,
type: Boolean,
}
},
computed: {
dataName() {
let mov = {}
this.moved ? mov.fill = 'blue' : mov.fill = 'red'
return mov
}
}
})
new Vue({
el: '#demo',
data() {
return {
moved: false
}
},
methods: {
changeMov() {
this.moved = !this.moved
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<button #click="changeMov">Change</button>
<Child :moved="moved" />
</div>
I have an input in a child component and when the user starts typing in the input it updates the data in the parent component, or should. This is my code, I can post other parts if useful.
Child
<input
:keyup="updateFilters(filters[data.field.key])"
:placeholder="data.label"
/>
methods: {
updateFilters(value) {
this.$emit("input", value);
}
}
Parent
data() {
return {
filters: {
name: "",
age: "",
address: "",
},
};
},
You can change the parent from child component the same way you do emiting other events like onchange, onkeyup, onkeydown etc.
Vue.component('parent', {
data() {
return {
parentValue: ''
};
},
template: `
<div>
<label>Parent state value:</label>
{{parentValue}}
<br/><br/>
<label>input is the child component:</label>
<br/>
<child #fromChild="fromChild"></child>
</div>
`,
methods: {
fromChild(value) {
this.parentValue = value
console.log(value) // someValue
}
}
})
Vue.component('child', {
template: `
<input
v-on:keyup="updateParent($event.target.value)"
placeholder="type something"
/>
`,
methods: {
updateParent(value) {
console.log(value)
this.$emit("fromChild", value);
}
},
})
new Vue({
el: "#app",
data: {
label: 'in Vue'
},
methods: {
toggle: function(todo) {
todo.done = !todo.done
}
}
})
I've prepared a working example here.
I want to change the format of this price IDR 50,000.00 to be like this IDR 50.000 using JS and Vue.
I got this script from this link but I don't understand how it works. I don't know what is this
replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")
so I can't change the format.
Vue.js
<template lang="html">
<div>
<input type="text" class="form-control" v-model="displayValue" #blur="isInputActive = false" #focus="isInputActive = true"/>
</div>
</template>
<script>
export default {
props: ["value"],
data: function() {
return {
isInputActive: false
}
},
computed: {
displayValue: {
get: function() {
if (this.isInputActive) {
// Cursor is inside the input field. unformat display value for user
return this.value.toString()
} else {
// User is not modifying now. Format display value for user interface
return "IDR " + this.value.toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")
}
},
set: function(modifiedValue) {
// Recalculate value after ignoring "$" and "," in user input
let newValue = parseFloat(modifiedValue.replace(/[^\d\.]/g, ""))
// Ensure that it is not NaN
if (isNaN(newValue)) {
newValue = 0
}
// Note: we cannot set this.value as it is a "prop". It needs to be passed to parent component
// $emit the event so that parent component gets it
this.$emit('input', newValue)
}
}
}
}
</script>
<style lang="css">
</style>
I changed this line
return "$ " + this.value.toFixed(2).replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1,")
to this
return "IDR " + this.value.toString().replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1\.")
Snippet:
Vue.component('my-currency-input', {
props: ["value"],
template: `
<div>
<input type="text" v-model="displayValue" #blur="isInputActive = false" #focus="isInputActive = true"/>
</div>`,
data: function() {
return {
isInputActive: false
}
},
computed: {
displayValue: {
get: function() {
if (this.isInputActive) {
// Cursor is inside the input field. unformat display value for user
return this.value.toString()
} else {
// User is not modifying now. Format display value for user interface
return "IDR " + this.value.toString().replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, "$1\.")
}
},
set: function(modifiedValue) {
// Recalculate value after ignoring "$" and "," in user input
let newValue = parseFloat(modifiedValue.replace(/[^\d\.]/g, ""))
// Ensure that it is not NaN
if (isNaN(newValue)) {
newValue = 0
}
// Note: we cannot set this.value as it is a "prop". It needs to be passed to parent component
// $emit the event so that parent component gets it
this.$emit('input', newValue)
}
}
}
});
new Vue({
el: '#app',
data: function() {
return {
price: 50000
}
}
});
body {
margin: 20px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
input {
border: 1px solid #888;
font-size: 1.2rem;
padding: 0.5rem;
}
<script src="https://unpkg.com/vue#2.1.5/dist/vue.js"></script>
<div id="app">
Price:
<my-currency-input v-model="price"></my-currency-input>
<p>
Price (in parent component): {{price}}
</p>
</div>
In case you are using jquery I would recommend using the jquery number format.
this allow you to automatic formatting of numbers in input elements as you type
Vue.component('idr', {
template: '<input type="text" class="form-control" v-model="txTotal"/>',
computed: {
txTotal: {
get() {
return this.value;
},
set(val) {
var rp = val.replace(/[^0-9]/g, '');
this.$emit('input', rp)
}
}
},
mounted() {
$(this.$el).number(true, 0, ',', '.')
}
})
new Vue({
el: '#app',
data: {
total: '',
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.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/df-number-format/2.1.6/jquery.number.min.js"></script>
<div id="app">
<idr #input="total = $event"></idr>
{{ total }}
</div>
UPDATE WITHOUT JQUERY
Vue.component('idr', {
template: '<input type="text" v-model="currentValue" #input="handleInput" />',
props: {
value: {
type: [String, Number],
default: ""
},
},
data: () => ({
currentValue: ''
}),
watch: {
value: {
handler(after) {
this.currentValue = this.format(after)
},
immediate: true
}
},
methods: {
format: value => (value + '').replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, "."),
handleInput() {
this.currentValue = this.format(this.currentValue)
this.$emit('input', (this.currentValue + '').replace(/[^0-9]/g, ""))
}
}
})
new Vue({
el: '#app',
data: {
total: 5000,
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<idr v-model="total"></idr>
{{ total }}
</div>
How do you go on passing objects as props on vue? I would imagine this would be a simple task but apparently not.
I have the following code on a .vue file:
// register the child component
Vue.component('component', {
props: {
data: {
type: Object
}
},
template: '<div>Data: {{data}}</div>',
mounted: function () {
console.log(this.data)
}
})
new Vue({
el: '#example'
})
<template>
<div id="example">
<component :data="msg"></component>
</div>
<template/>
<script>
export default{
data(){
return{
msg:{}
}
},
created(){
this.msg = { x: 6}
}
}
<script/>
Vue.component('component', {
props: {
data: {
type: Object,
default: () => ({
x: Number
})
}
},
template: '<div>Data: {{data.x}}</div>',
mounted: function () {
console.log(this.data)
}
})
new Vue({
el: '#example'
})
try this you use x but you never put default in it
How to binding parent's model to child in Vue.js?
These codes below is works fine. if i fill the input manually, then child's model return it's value to the parent's model.
But the issue is, if the data set from AJAX request in a parent, the input doesn't automatically filled.
Can anyone help me on this?
Form.vue
<template>
<form-input v-model="o.name" :fieldModel="o.name" #listenChanges="o.name = $event"/>
<form-input v-model="o.address" :fieldModel="o.address" #listenChanges="o.address = $event"/>
</template>
<script>
import FormInput from '../share/FormInput.vue'
export default {
data () {
return {
o: {
name: '',
address: ''
}
}
},
components: { 'form-input': FormInput },
created: function() {
axios.get('http://api.example.com')
.then(response => {
this.o.name = response.data.name
this.o.address = response.data.address
})
.catch(e => { console.log(e) })
}
}
</script>
FormInput.vue
<template>
<input type="text" v-model='fieldModelValue' #input="forceUpper($event, fieldModel)">
</template>
<script>
export default {
props: ['fieldModel'],
data() {
return {
fieldModelValue: ''
}
},
mounted: function() {
this.fieldModelValue = this.fieldModel;
},
methods: {
forceUpper(e, m) {
const start = e.target.selectionStart;
e.target.value = e.target.value.toUpperCase();
this.fieldModelValue = e.target.value.toUpperCase();
this.$emit('listenChanges', this.fieldModelValue)
}
}
}
</script>
Things are more straightforward if you take advantage of v-model in components.
If you put v-model on a component, the component should take a prop named value, and should emit input events to trigger it to update.
I like to make a computed to hide the event emitting, and allow me to just v-model the computed inside my component.
new Vue({
el: '#app',
data: {
o: {
name: '',
address: ''
}
},
components: {
'form-input': {
template: '#form-input',
props: ['value'],
computed: {
fieldModelValue: {
get() {
return this.value;
},
set(newValue) {
this.$emit('input', newValue.toUpperCase());
}
}
}
}
},
// Simulate axios call
created: function() {
setTimeout(() => {
this.o.name = 'the name';
this.o.address = 'and address';
}, 500);
}
});
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
Name ({{o.name}})
<form-input v-model="o.name"></form-input>
Address ({{o.address}})
<form-input v-model="o.address"></form-input>
</div>
<template id="form-input">
<input type="text" v-model='fieldModelValue'>
</template>
The mounted() hook is blocking subsequent updates from the parent.
Remove mounted and change v-model to 'fieldModel'
<template>
<input type="text" :value='fieldModel' #input="forceUpper($event, fieldModel)">
</template>
<script>
export default {
props: ['fieldModel'],
data() {
return {
fieldModelValue: ''
}
},
// mounted: function() {
// this.fieldModelValue = this.fieldModel;
// },
methods: {
forceUpper(e, m) {
const start = e.target.selectionStart;
e.target.value = e.target.value.toUpperCase();
this.fieldModelValue = e.target.value.toUpperCase();
this.$emit('listenChanges', this.fieldModelValue)
}
}
}
</script>
Demo CodeSandbox