The condition works in a strange way.
need request "A" if true, and request "B" if false.
<input type='checkbox' :value='category.title' v-model='checkedCategories' #change='changeEvent'>
js:
changeEvent($event) {
if($event.target.checked) {
this.forChange = true;
} else {
this.forChange = false;
}
},
requests
request() {
if(this.forChange) {
axios.get('link', {params: a, b, c })
} else {
axios.get('link', {params: a, c})
}
}
What's wrong?
upd:
The condition starts to be triggered only after the third click. The first two give true
You need to define forChange in your data section, and your checkbox should bind to the checked property, or the v-model.
Once you have the binding, you don't really need the method.
<input type='checkbox' v-model='forChange'>
or
<input type='checkbox' :checked='forChange' #change='forChange=$event.target.checked'>
Using both :value and v-model at the same time will cause issues, and is probably the root of your problem.
Related
In a page i am fetcing data from API and showing the data in the text field. After that user can change the data and submit the form. I am uanble to show data using :value in the inout field. Its showing conflicts with v-model on the same element because the latter already expands to a value binding internally
I tried to mount the data after it loads. But it is still not showing.
<input v-model="password" :value="credentials.password">
created() {
let txid = this.$route.params.id
this.$axios.get(this.$axios.defaults.baseURL+'/v1/purno/internal/users/'+ txid, {
}).then((response) => {
if (response.data.status == 'error') {
toast.$toast.error('Something Went Wrong at!', {
// override the global option
position: 'top'
})
} else if (response.data.status == 'success') {
if(response.data.data.found ==true) {
this.credentials = response.data.data;
})
}
}
})
});
},
data(){
return {
credentials:[],
password:null
}
},
mounted(){
this.password = this.credentials.password
}
How can i solve this problem? Thanks in advance
Please complete it within the request callback
this.credentials = response.data.data;
this.password = this.credentials.password;
like this in the then callback fn. Try it!
conflicts with v-model on the same element because the latter already expands to a value binding internally error message tells it all
v-model="password" is same as :value="password" #input="password = $event.target.value" (for text and textarea - see here)
So using it together with another :value makes no sense...
I'm creating a form using vue.js and I need to create inputs in vue that is always capitalized. I know I could use the css property
text-transform: uppercase;
and then transform the data before sending using
data.someData.toUpperCase()
But I wonder if there is a more intelligent way of doing that in vue.js. In react we can create controlled inputs and easily do it. Is there anything like that in Vue.js?
I managed to do it using computed fields, however, I would have to create computed getter and setter for each input in the form. Is there a better way of doing it?
You could create a custom directive.
Vue.directive( 'touppercase', {
update (el) {
el.value = el.value.toUpperCase()
},
})
And then use it where you need. For example:
<input type="text" v-model="modelfield" v-touppercase>
Since you don't have a lot of code to run, you should manually bind events to your textfield and then handle the uppercasing there.
Handling events from a text field can be done by adding an input event handler on them, and then updating the initial state again.
<input :value="text" #input="updateText($event.target.value)"/>
export default {
data() {
return {
text: '',
}
},
methods: {
updateText(newValue) {
this.value = newValue.toUpperCase();
},
}
}
You can also do it inline in a template, but this might make it harder to read depending on your code style preferences
<input :value="text" #input="text = $event.target.value.toUpperCase()"/>
This directive works fine with v-model (last character is in upper case too):
Vue.directive('uppercase', {
update(el) {
const sourceValue = el.value;
const newValue = sourceValue.toUpperCase();
if (sourceValue !== newValue) {
el.value = newValue;
el.dispatchEvent(new Event('input', { bubbles: true }));
}
},
});
Usage:
<input type="text" v-model="myField" v-uppercase />
You can do this:
<input :value="theValue" #input="theValue = theValue.toUpperCase()"/>
as a fix for asologor's answer you should reach input element to change it at vuetify
Vue.directive("uppercase", {
update(el) {
const sourceValue = el.getElementsByTagName("input")[0].value
const newValue = sourceValue.toUpperCase()
if (sourceValue !== newValue) {
el.getElementsByTagName("input")[0].value = newValue
el = el.getElementsByTagName("input")[0]
el.dispatchEvent(new Event("input", { bubbles: true }))
}
}
})
and usage is
<v-text-field
type="text"
outlined
placeholder="placeholder"
v-model="name"
prepend-inner-icon="edit"
v-uppercase
/>
this is defnetely working
I have few inputs with submit button. Have some validation logic that adds 'has-error' class to input. How can i unset this class on focus?
Template:
<div class="input-styled badge-icon" :class="{ 'has-error': errors.email}">
<input type="text" #focus="delete errors.email" v-model="email" placeholder="example#gmail.com">
</div>
<button #click="submit">Submit</button>
JS
data() {
return {
errors: {},
email: ''
}
},
methods: {
submit(){
this.errors = {};
if(!this.email){
this.errors.email = 'Something';
}
}
}
I'm trying delete error property, trying #focus='errors.email="" ', but class 'has-error' disappears only when i'm typing something on inputs. #focus event works and i think that i should call some function that will update my DOM?
It is a good practice to move operations on component's data to functions. You can achieve desired validation reset, by creating a resetValidation function and binding it to focus event on input field.
Method itself should reset errors field to falsy values. Example below assumes, there are multiple input fields in the form. Each field should call resetVlidation method with corresponding error field name. If no field is provided, we can reset validation as whole:
resetValidation (field) {
if (field) {
this.errors = {
...this.errors,
[field]: ''
}
} else {
this.errors = {}
}
Please, check the working example below:
codesandbox
I need to create a checkbox that will be checked/unchecked depending on the value of a parameter coming from the database.
I'm not able to load that value when I'm rendering the page, so the idea is: render the page, "tell" the checkbox to "ask" the server what is the current value of the parameter and then check/uncheck the checkbox depending on the response. Then, if the user checks/unchecks the checkbox, make a new Ajax request to update the value in the database.
I wrote some code (I'm new in Vuejs, so for sure I'm doing something wrong):
var vm = new Vue({
el: '#root',
computed: {
checked() {
return this.initialize()
},
value() {
return this.checked
}
},
watch: {
checked() {
alert('watcher')
this.update();
}
},
methods: {
initialize(){
// Just pretending an initial value
var randomBoolean = Math.random() >= 0.5;
alert('Ajax request here to initialize it as ' + (randomBoolean ? 'checked' : 'unchecked'));
return randomBoolean;
},
update(){
alert('ajax request here to set it to ' + this.value)
}
}
});
You can check and run the code here: https://jsfiddle.net/hyn9Lcv2/
Basically it works to initialize the checkbox, but then it fails to update. If you check the console, there is this error:
[Vue warn]: Computed property "checked" was assigned to but it has no setter.
First have you thought of using the created() hook from the vue instance instead of watcher?
It's recommended and will execute the code as soon as the component is created.
From the doc:
new Vue({
data: {
a: 1
},
created: function () {
//Ajax call:
//onsuccess(response){
this.a = reponse.data.a
}
}
})
in the created hook you can do your ajax call, (axios is good library for that, worth checking it out: https://github.com/axios/axios ).
Then from your ajax response you can link the desired value to your checkbox by assigning it to a variable in the data object of the instance (in our case 'a')
Then bind it to your checkbox with the v-model like this:
<input
type="checkbox"
v-model="a">
I recommend to check the vue doc for more info on biding: https://v2.vuejs.org/v2/guide/forms.html#Checkbox-1
Hope it helps.
Just add bind click event
<div id="root">
<input id="check" type="checkbox" name="active" v-model="checked" #click="update">
<label for="check">Click me</label>
</div>
You need to fetch the database value when the component is created or mounted.
You then need to bind your checkbox with the initialized data.
Finally you need to watch the data to send an update to the database.
var vm = new Vue({
el: '#root',
data: {
//Your data
checked: null
},
// Function where you are going to fetch your data
mounted: function () {
console.log("Ajax call to initialize");
this.checked = Math.random() >= 0.5;
},
watch: {
// Watcher to save your data in the database
checked: function(newValue, oldValue){
if (oldValue === null) { return; } // to not make an useless update when data has been fetched
console.log("Ajax call to update value " + newValue);
}
}
});
<div id="root">
<input id="check" type="checkbox" name="active" v-model="checked" :disabled="checked === null">
<label for="check">Click me</label>
</div>
To fetch your data you can use for example Axios that works great with Vue.
To know more about life cycle of a component (to know if you should do the fetching at created or mounted) : https://v2.vuejs.org/v2/guide/instance.html
I'm building a multi-step form in Aurelia where each page shows one question.
I use the same view for every question, with if statements determining what type of form field to show.
When I try to bind my question data to a multiple select element however, Aurelia throws errors and says "Only null or Array instances can be bound to a multi-select.".
What's really strange is that if the first question is a multiple select I don't get the error until I come to a non-multiselect question and then go back to the multiselect question.
I can solve this entire problem by setting activationStrategy: 'replace' for this route, but I really don't want that.
The important code follows:
import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';
#inject(Router)
export class Form {
constructor (router) {
this.router = router;
this.active = 0;
this.field = null;
this.fields = [
{
type: 'text',
value: null
},
{
type: 'select',
value: [],
options: [
'foo',
'bar'
]
},
{
type: 'select',
value: [],
options: [
'foo',
'bar'
]
},
{
type: 'text',
value: null
},
];
}
activate (routeParams) {
this.active = routeParams.fieldIndex || 0;
this.active = parseInt(this.active);
this.field = this.fields[this.active];
}
prev () {
if (typeof this.fields[this.active - 1] !== 'undefined') {
this.router.navigateToRoute('form', {
fieldIndex: this.active - 1
});
return true;
}
else {
return false;
}
}
next () {
if (typeof this.fields[this.active + 1] !== 'undefined') {
this.router.navigateToRoute('form', {
fieldIndex: this.active + 1
});
return true;
}
else {
return false;
}
}
}
And the template:
<template>
<div class="select" if.bind="field.type == 'select'">
<select value.bind="field.value" multiple="multiple">
<option repeat.for="option of field.options" value.bind="option">${option}</option>
</select>
</div>
<div class="text" if.bind="field.type == 'text'">
<input type="text" value.bind="field.value">
</div>
<a click.delegate="prev()">Previous</a> | <a click.delegate="next()">Next</a>
</template>
But you'll probably want to check out the GistRun: https://gist.run/?id=4d7a0842929dc4086153e29e03afbb7a to get a better understanding.
Try setting the first question to a multiselect and you'll notice the error disappears (until you go back to it). You can also try activationStrategy in app.js like mentioned above.
Why is this happening and how can I solve it?
Also note that in my real app I'm actually using compose instead of ifs but have tried with both and both produce the same error. It almost seems as if the select values are bound before the if is evaluated, causing the error to show up because the text field type lacks the options array.
A little late but I wanted to give a suggestion -- for SELECT multi-selects, you should decouple the bound variable from the multi-selector to prevent those errors.
For example, if you in your custom elements that bind to 'selected', they should bind to:
<select multiple value.two-way="selectedDecoupled">
Then when the actual variable 'selected' changes, it only changes in the custom element if the bound value is an array:
selectedChanged( newV, oldV ){
if( typeof newV =='object' )
this.selectedDecoupled = newV;
else
this.selectedDecoupled = [];
$(this.SELECT).val(this.selectedDecoupled ).trigger('change');
}
Example of it in use with a custom select2 element:
https://github.com/codefreeze8/aurelia-select2
Ok so it turns out swapping the order of the HTML, and putting the select after the input solves this issue.
Jeremy Danyow explains it like this:
When Form.field changes, the bindings subscribing to that property's changes evaluate sequentially. Which means there's a period of time when the select AND the input are both on the page. The html input element coaleses null values to empty string which in turn causes field.value to be empty string, which makes the multi-select throw.
Very tricky to track down imo but I'm glad the Aurelia devs are so helpful over on Github.
Working Gist: https://gist.run/?id=3f88b2c31f27f0f435afe14e89b13d56