I have a little task in vue.js and I want to change the syntax of v-model to model, or something else with webpack and vue-loader. I tried directives but that's not what I need.
This my example:
<input v-model="anyVarible">
<input model="anyVarible">
v-model is just a syntax sugar on setting & getting the data - prepared for all the input types:
You can use the v-model directive to create two-way data bindings on
form input, textarea, and select elements. It automatically picks the
correct way to update the element based on the input type. Although a
bit magical, v-model is essentially syntax sugar for updating data on
user input events, plus special care for some edge cases.
Source: Vue 2 v-model
That means, you can change v-model to something else, but then you have to handle the cases:
new Vue({
el: "#app",
data() {
return {
vmodeltext: null,
modeltext: null,
vmodelcb: null,
modelcb: null,
}
},
methods: {
handleInputText({
target: {
value
}
}) {
this.modeltext = value
},
handleInputCb({
target: {
checked
}
}) {
this.modelcb = checked
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="vmodeltext" /><br /> With v-model: {{ vmodeltext }}<br />
<hr />
<input type="text" :value="modeltext" #input="handleInputText($event)" /><br /> With modeltext: {{ modeltext }}<br />
<hr />
<input type="checkbox" v-model="vmodelcb" /><br /> With v-model: {{ vmodelcb }}<br />
<hr />
<input type="checkbox" :checked="modelcb" #change="handleInputCb($event)" /><br /> With modelcb: {{ modelcb }}<br />
</div>
So, essentially you don't need to change v-model with Webpack or a loader - just write the code in the way you need.
Related
I have a simple FormComponent:
<template>
<form>
<fieldset>
<slot />
</fieldset>
<span v-if="!isEditing" #click="edit()">Edit</span>
</form>
</template>
<script>
export default {
data () {
return {
isEditing: false,
}
},
methods: {
edit (state) {
this.isEditing = !this.isEditing
}
}
}
</script>
And when I use the component:
<FormComponent>
<input value="Man" type="text" :disabled="!isEditing">
</FormComponent>
The input field are correctly slotted into the component but the :disabled="!isEditing" from the slot isn't reacting to the change of isEditing in the FormComponent.
The Vue documentation is pretty good, but it doesn't cover each edge case.
The component with the <slot></slot> tag has to bind the data onto an attribute on the <slot> tag, like a prop:
<slot :isEditing="isEditing"></slot>
Then when you render that slotted component, Vue creates and exposes an object containing all of the bound data, with each attribute having a property on that object.
Access the object by adding an expression to the v-slot directive in this format:
<FormComponent v-slot:default="slotProps">
(Or use the alias # as in #default="slotProps".) You can access individual properties like isEditing via that object, like slotProps.isEditing:
<FormComponent #default="slotProps">
<input value="Man" type="text" :disabled="!slotProps.isEditing">
</FormComponent>
Here's the more common (and versatile) <template> syntax:
<FormComponent>
<template #default="slotProps">
<input value="Man" type="text" :disabled="!slotProps.isEditing">
</template>
</FormComponent>
You can also destructure slotProps for more direct access to the properties:
<FormComponent>
<template #default="{ isEditing }">
<input value="Man" type="text" :disabled="!isEditing">
</template>
</FormComponent>
I'm currently trying to change the default invalid text from form inputs using the code below. The way I'm trying to do it works if the text is static but in my case, the text must be dynamic so I have to put in some sort of prop/data value instead. This is because users will have the ability to toggle between English and Chinese text. I've tried using #invalid and :oninvalid but those don't seem to work. Would anyone be able to help me get through this issue?
<input
ref="firstInput1"
type="email"
v-model="email"
oninvalid="this.setCustomValidity('custom text on invalid')"
onchange="this.setCustomValidity('')"
:placeholder="Email"
required
/>
oninvalid and onchange are the two key components to making this work. Hopefully we can find out how to do this with dynamic text.
For change event in Vue input you should use #change (not onchange)
And I think this sample can help you to set vue validation on email
<div class="container" id="app">
<div :class="['input-group', isEmailValid()]">
<span class="input-group-addon" id="basic-addon1"><span class="fa fa-envelope"></span></span>
<input type="email" class="form-control" placeholder="Email Address" v-model="email" />
</div>
</div>
and
new Vue({
el: '#app',
data: {
email: '',
reg: /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,24}))$/
},
methods: {
isEmailValid: function() {
return (this.email == "")? "" : (this.reg.test(this.email)) ? 'has-success' : 'has-error';
}
}
});
I am currently creating a form that has an unknown number of sensor fields within it. I've gotten the front end working beautifully. However, now I want to grab the user info out of those dynamically generated component fields and I can't figure out how. Here is where I'm generating the components:
{this.state.sensors.map((item, i) => (
<UpdateSensorInfo
key={i}
sensorName={item.sensorName}
sensorLowerLimit={item.sensorLowerLimit}
sensorUpperLimit={item.sensorUpperLimit}
/>
))}
And here is the actual component itself:
import React, { Component } from "react";
import "./updateSensorInfo.css";
class UpdateSensorInfo extends Component {
render() {
return (
<div>
<div className="sensorInfoFrame">
<div className="sensorFieldBody">
<label className="sensorTextFieldLabel">Sensor Name:</label>
<input
type="text"
name="text"
placeholder=""
className="sensorTextField"
defaultValue={this.props.sensorName}
required
/>
</div>
<div className="sensorFieldBody">
<label className="sensorTextFieldLabel">Sensor Upper Limit:</label>
<input
type="number"
name="text"
placeholder=""
className="sensorTextField"
defaultValue={this.props.sensorUpperLimit}
required
/>
</div>
<div className="sensorFieldBody">
<label className="sensorTextFieldLabel">Sensor Lower Limit:</label>
<input
type="number"
name="text"
placeholder=""
className="sensorTextField"
defaultValue={this.props.sensorLowerLimit}
required
/>
</div>
</div>
</div>
);
}
}
export default UpdateSensorInfo;
I would like to uniquely identify each text field within each generated component. How can I do this?
For anyone who has a similar situation, I have found a solution that works. There is a way to use the key that is created for each of the components within each component. use the following as an id or name for the input element:
id={`${this._reactInternalFiber.key}-additionalNameHere`}
This uses the key and will allow you to loop over the inputs within the components.
I'm building a form builder in Vue which allows users to add/remove various types of input. My method so far is to have a template component for each input type, then when a user selects that input type I push it into an array on the parent component to loop over and display.
However, I also need to pass the value of the input up to the parent (and store it in the input type="hidden" element), so I'm emitting an event in the child component and catching it in the parent. My problem is that the value of labelText gets updated identically for every input type="hidden" at once when I type, rather than individually. I can't work out what I'm missing?
Text input template
<template>
<div id="TextInput">
<input type="text" placeholder="Question" class="form__input_label" #input="sendLabelUp($event.target.value)" />
<input type="text" placeholder="Test placeholder" />
<slot name="removeField"></slot>
<slot name="hiddenInputs"></slot>
</div>
</template>
<script>
export default {
name: 'TextInput',
methods: {
sendLabelUp: function(val) {
this.$emit('input', val);
},
},
};
</script>
Parent template (just including the part I think is relevant)
<transition-group name="form__input_list" tag="div">
<component :is="input.type" v-for="(input, index) in inputs" v-bind="input" :key="input" v-model="labelText" class="form__input">
<div slot="removeField">
<a class="btn btn--tertiary sml-push-top-half" #click="removeField(index)">Remove</a>
</div>
<div slot="hiddenInputs">
<!-- Hidden inputs used to store question config -->
<input type="hidden" :name="`pages[0]questions[${index}]type[${input.type}]label[${labelText}]`" />
</div>
</component>
</transition-group>
<script>
export default {
name: 'InputGenerator',
components: {
TextInput,
TextArea,
NumberInput,
LikertScale,
},
data() {
return {
inputs: [],
dropdownActive: false,
labelText: '',
};
},
};
</script>
I have created a vuejs2 app using vue-cli. I'm trying to bind dynamic value for checkbox as vuejs documentation said: value binding. But its giving me undefined. If I don't bind vlaue its giving me true or false. This is my ValueBinding.vue component.
<template>
<div id="input">
<p> Selected value for smoking: {{ smoking }} </p>
<input v-model="smoking" v-bind:true-value="Y" v-bind:false-value="N" type="checkbox">
<label>No Smoking</label>
<br>
<button #click="submit">Submit</button>
</div>
</template>
<script>
export default {
name: 'value-binding',
data() {
return {
smoking: ''
}
},
methods: {
submit() {
console.log(this.smoking) //shows undefined
}
}
}
</script>
I'm new to vuejs. Thanks in advance.
When you use v-bind, it dynamically bind one or more attributes to an expression. In your case when you do
v-bind:true-value="Y"
It will try to find a data attribute: Y in vue instance, as you have not defined any such attribute, it will become undefined.
If you just want to true-value as "Y" and false-value as "N", do follwing:
<input v-model="smoking" true-value="Y" false-value="N" type="checkbox">