I am currently using Vue Js with Vuetify and Vuelidate for an SPA.
I have a form to create a new Account, which is pretty standard.
What I have decided to do though is break the form into steps and utilise the v-stepper component from Vuetify.
The part I am stuck on is how the users choices as they fill in the form can dictate the steps. For example;
Using a v-if I determine if the v-text-field is needed to be shown, what I am unsure of is how this will effect the forms data/model that will eventually be sent in a POST.
Am I looking at this in the right way? or can someone suggest a better approach?
Code:
<template>
<v-form v-model="stepCount">
<-stepper-header>
<v-stepper-step step="1" :complete="stepStage > 1">
Account Details
</v-steper-step>
<v-divider></v-divider>
<v-stepper-step step="2" :complete="stepStage > 2">
Personal Details
</v-steper-step>
</v-stepper-header>
<v-stepper-content step="1">
<v-text-field>
Usual filler for a text field {Username}
</v-text-field>
<v-text-field>
Usual filler for a text field {Password}
</v-text-field>
<v-text-field>
Usual filler for a text field {Age}
</v-text-field>
<v-text-field>
label="Gender"
v-model="gender
:error-messages="genderErrors"
#intput="v.gender.$touch()"
#blur="v.gender.$touch()"
</v-text-field>
</v-stepper-content>
<v-stepper-content>
<v-text-field v-if="gender == 'F'">
label="Bra Size"
v-model="braSize
:error-messages="braSizeErrors"
#intput="v.gender.$touch()"
#blur="v.gender.$touch()"
</v-text-field v-else>
<v-text-field>
Usual filler for a text field {t-ShirtSize}
</v-text-field>
</v-stepper-content>
Thanks in advance.
It seems like your asking several things here so here is what I think the answer your looking for is.
To control the stepper flow you can either set the stepStage to variables like steppers shows or use a computed variable that returns the state based on the collected data.
Computed state
computed:{
stepStage(){
if(/*certain content is correctly filled and a next button has been clicked*/)return 1
if(/*check another computed variable that decides if the form is complete*/)return 2
//etc
}
}
As far as v-if statements in forms. It shouldn't affect a submitted form since it actually removes or inserts an element based on the value as stated in the first paragraph of this section. Note v-stepper doesn't use v-if.
For more control you may consider saving the data in the state of the component and then use javascript to do the actual submission. This allows you to have complete control over what is sent to the server.
Related
Version info: Vuetify 2.6.3, Vue 2.6.14, Nuxt 2.15.8
I'm making a custom component that is supposed to be somewhat similar to v-autocomplete, except that it's rendered as bottom sheet. If user enters a display filter into v-text-field, the option list (v-list) is supposed to display only those options that match the filter.
In overall it works fine except one use case: let say the list has 5 items (aa, bb, cc, dd, ee) and user selected bb and cc from the list. Now, v-list-item-group's model selectedItems contains the 2 selected items bb and cc, perfect! However, when user enters b into display filter, the already selected item cc will be auto deleted from selectedItems. I can't tell if selectedItems change is caused by filter or by user selection. Is there a way to maintain the selection in model?
I'm considering a hack - if an item is selected, keep it in filteredChoices even if it does not match the filter. This behaviour is bearable but UX wise not as intuitive as the filter of v-autocomplete.
The simplified structure looks like the below:
<template>
<v-bottom-sheet scrollable>
<v-card>
<v-card-text>
<v-list>
<v-list-item-group
v-model="selectedItems"
:mandatory="!optional"
:multiple="multiple"
>
<v-list-item
v-for="item in filteredChoices"
:key="item.value"
:value="item"
>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card-text>
<v-text-field
v-model="filterInput"
placeholder="filter choices..."
hide-details
></v-text-field>
</v-card>
</v-bottom-sheet>
</template>
<script>
...
filteredChoices() {
if (this.filterInput == null) {
return this.allItems
}
return this.allItems.filter((item) => {
return item.label
.toLocaleLowerCase()
.includes(String(this.filterInput).toLocaleLowerCase())
})
},
...
</script>
How I reach the solution:
I was quite new to front-end stuff. Previously, when I was learning how to implement v-model support for custom component, all web resources I came across say the same thing - bind inner component's value props to custom component's value props. However I just discovered that this is merely one of the ways rather than a must. With that new learning, more possibilities pop up in my mind and one of them lead me to below solution.
Solution:
Decouple the custom component value from bottomsheet's list
Bind the model of inner v-autocomplete to an array data, say internalValue. (this inner component is not included in question's template for simplification)
Bind the model of inner v-list-item-group (in bottomsheet) to a separate data, say bottomSheetSelections.
Update the custom component value based on user actions in bottomsheet
Add a watcher to bottomSheetSelections array:
if the array grows, it means the user has selected more item. We should push the additional item to internalValue.
if the array shrinks:
if the missing item is still there in filteredChoices, the removal is triggered by user de-selection. We should remove this item from internalValue.
else, we consider the removal is triggered by list filter. No action is needed.
Restore user selection in bottomsheet on clearing filter
Add a watcher for filteredChoices. Whenever the array grows, if the additional choice exist in internalValue, we should push it to bottomSheetSelections.
Summary
Strictly speaking, this doesn't solve the ask of question's title - the list selection in bottomsheet (bound to v-list-item-group) is still getting reset. However, at least we're able to restore it in bottomsheet on clearing filter.
More importantly, this solution achieved the objective mentioned in question details - retain the user selection value. We kept it in a separate data internalValue.
I haven't test this solution with long list of data. My guts feeling is that there could be more efficient solution. Please share it if you have a better solution.
I'm trying to change the default checked button in my form according to the database data
I can acess this data with
item.france
or
france
So I want to change the default checked button according to the data stored in my database, the problem is that when I apply the attribute "mandatory" to my v-radio-group I can't change the default checked button even If I try to add :checked="true"
<v-radio-group v-model="item.france" row mandatory>
<template v-slot:label>
<div>France</div>
</template>
<v-radio label="Oui" :checked="false"></v-radio>
<v-radio label="Non" :checked="true"></v-radio>
</v-radio-group>
Is there a way to change the default checked, and also a way to change it's value according to my data.
Any help is greatly appriciated, thanks !
the question I have might be hard to understand, so please help me re-organize the question if you can see the better way to put it in.
So, I am building a registration platform.
(1) First, I receive an array of objects of cases the user can sign time to.
(2) Each object consists of 2 properties, "name", "description".
(3) I store the array in the data, end use it in the element provided by a picker called "vue-multiselect", which basically accepts the array and loops over the objects and displays them.
(4) As you can see, it displays both properties and values, which I am trying to avoid. My question is, is it possible to pass only the "name" value into the picker, and display the description value when hovering the first value?
You can find this use case documentation here: https://vue-multiselect.js.org/#sub-custom-option-template
<multiselect v-model="value"
deselect-label=""
select-label=""
placeholder=""
selected-label=""
:show-pointer="true"
:options="projectCases">
<template slot="option" slot-scope="{ option }">
<strong :title="option.description">{{ option.name }}</strong>
</template>
</multiselect>
ps: I use title attribute to implement display-on-hover functionality. you can use any other tooltip library as well.
I need to get the entire array element that makes up the Autocomplete item, I want the element so I can store it in Veux without store each item, such as first name, MI last name etc. I'm going to build upon another question that was very similar that was posted here Vuetify v-select get item index and with the jsfiddle answer solution
my code that I'm using is:
<v-list-tile>
<v-autocomplete
v-model="data"
:allow-overflow="false"
:items="named_items"
:item-text="getFullName"
:loading="loadingMembers"
:debounce-search="0"
:search-input.sync="searchInput"
class="purple-input search-input"
default
color="purple"
autofocus
placeholder="Search..."
item-value="MemberID"
hide-no-data
no-data-text="Add New Member"
#change="changeMember"
#keyup.enter="hitEnter"
/>
</v-list-tile>
the jsfiddle is at https://jsfiddle.net/Roland1993/fg461d55/1/
and my question is when an item is selected is it possible to get the element that makes up the ID, Question and Answers? so the it can be stored as an array?
It is entirely possible, for example, you have already bound to events, but you can have the name or values of their targets.
See: Method Event handlers
I'm learning Vue with an online course and the instructor gave me an exercise to make an input text with a default value. I completed it using v-model but, the instructor chose v-bind:value and I don't understand why.
Can someone give me a simple explanation about the difference between these two and when it's better use each one?
From here -
Remember:
<input v-model="something">
is essentially the same as:
<input
v-bind:value="something"
v-on:input="something = $event.target.value"
>
or (shorthand syntax):
<input
:value="something"
#input="something = $event.target.value"
>
So v-model is a two-way binding for form inputs. It combines v-bind, which brings a js value into the markup and v-on:input to update the js value. The js value must be present in your data, or in an inject.
Use v-model when you can. Use v-bind/v-on when you must :-) I hope your answer was accepted.
v-model works with all the basic HTML input types (text, textarea, number, radio, checkbox, select). You can use v-model with input type=date if your model stores dates as ISO strings (yyyy-mm-dd). If you want to use date objects in your model (a good idea as soon as you're going to manipulate or format them), do this.
v-model has some extra smarts that it's good to be aware of. If you're using an IME ( lots of mobile keyboards, or Chinese/Japanese/Korean ), v-model will not update until a word is complete (a space is entered or the user leaves the field). v-input will fire much more frequently.
v-model also has modifiers .lazy, .trim, .number, covered in the doc.
In simple words
v-model is for two way bindings means: if you change input value, the bound data will be changed and vice versa.
but v-bind:value is called one way binding that means: you can change input value by changing bound data but you can't change bound data by changing input value through the element.
check out this simple example: https://jsfiddle.net/gs0kphvc/
v-model
it is two way data binding, it is used to bind html input element when you change input value then bounded data will be change.
v-model is used only for HTML input elements
ex: <input type="text" v-model="name" >
v-bind
it is one way data binding,means you can only bind data to input element but can't change bounded data changing input element.
v-bind is used to bind html attribute
ex:
<input type="text" v-bind:class="abc" v-bind:value="">
<a v-bind:href="home/abc" > click me </a>
v-model is for two way bindings means: if you change input value, the bound data will be changed and vice versa. But v-bind:value is called one way binding that means: you can change input value by changing bound data but you can't change bound data by changing input value through the element.
v-model is intended to be used with form elements. It allows you to tie the form element (e.g. a text input) with the data object in your Vue instance.
Example: https://jsfiddle.net/jamesbrndwgn/j2yb9zt1/1/
v-bind is intended to be used with components to create custom props. This allows you to pass data to a component. As the prop is reactive, if the data that’s passed to the component changes then the component will reflect this change
Example: https://jsfiddle.net/jamesbrndwgn/ws5kad1c/3/
Hope this helps you with basic understanding.
There are cases where you don't want to use v-model. If you have two inputs, and each depend on each other, you might have circular referential issues. Common use cases is if you're building an accounting calculator.
In these cases, it's not a good idea to use either watchers or computed properties.
Instead, take your v-model and split it as above answer indicates
<input
:value="something"
#input="something = $event.target.value"
>
In practice, if you are decoupling your logic this way, you'll probably be calling a method.
This is what it would look like in a real world scenario:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input :value="extendedCost" #input="_onInputExtendedCost" />
<p> {{ extendedCost }}
</div>
<script>
var app = new Vue({
el: "#app",
data: function(){
return {
extendedCost: 0,
}
},
methods: {
_onInputExtendedCost: function($event) {
this.extendedCost = parseInt($event.target.value);
// Go update other inputs here
}
}
});
</script>