Why are my Vue/Nuxt Select field states valid by default? - vue.js

I have a variety of HTML select elements inside of Nuxt.js. I'm also using Vuelidate for validation and this is working as expected. This is a typical select box in my form:
<select
id="location"
name="location"
v-model="form.location"
#blur="$v.form.location.$touch()"
:class="{error: appendErrorClass($v.form.location)}"
>
<option :value="null" hidden>Choose...</option>
<option
v-for="(item, index) in $store.state.quotes.data.practiceStates"
:key="index"
:value="item.data">
{{item.display}}
</option>
</select>
Before selecting any of the options, I'm noticing the following on all select fields.
I've tried removing any Vue magic on a test select field to see if the same results happen.
<select id="location1" name="location1">
<option value="" hidden>Choose...</option>
<option value="one">one</option>
<option value="two">two</option>
<option value="three">three</option>
</select>
Still seeing valid: true. Is there anything I'm overlooking that would cause the validity to default to true? Thanks in advance for any help or guidance on this issue.
UPDATE For Clarification:
Vuelidate validation works just fine. The issue I'm dealing with is the select field property Validity.validate. I only mention Vuelidate to give full context.

HTML Select is a sort of "strange" form element in that validity is typically checking to see if there's a readable value. Since a select always has something picked, it validates...
This is different from say a telephone input that has a specific pattern required to be valid.
I haven't used Vuelidate specifically, but I read the docs as saying, if you left the v-model="form.location" there's a good chance it's simply validating that a value exists so Any selcted item would qualify.

In my original post, I referenced the dynamic style based on the vuelidate library: :class="{error: appendErrorClass($v.form.location)}"
#PierreSaid responded to this post and later deleted his/her reply. Turns out, his response was helpful in pointing me to some Vuelidate attributes that were able to assist in a workaround for my issue. Thank you, PierreSaid.
I have since updated that dynamic class to be a mixin that looks like this:
export default {
methods: {
appendErrorAndValidityClass(field) {
return {
error: field.$error,
invalid: field.$invalid,
};
}
}
};
After importing the mixin into the Vue partial, my select box looks like this:
<select
id="location"
name="location"
v-model="form.location"
#blur="$v.form.location.$touch()"
:class="appendErrorAndValidityClass($v.form.location)"
>
This appends a class of invalid when the select field has not been updated. It also updates the error style accordingly. Now, I can assign styles for when the select field has an invalid class. This solves the overall issue for me. Thanks for your help PierreSaid and Bryce.

Related

How can I use the selected prop in a <select> that has a v-model?

Problem:
I have a <select> that uses a v-model to save the selected options into an array. The problem is that I can't use the selected properties on one of the <options> because the v-model ingores that and instead uses the bound JavaScript as it's source of truth.
What I have tried:
I tried looking up my problem on StackOverflow and I have found two questions but they didn't really help nor explain why and how. Here are the posts I have looked at:
using v-model on makes first option not appear in select - I tried this but nothing changed. My selected appear as selected but it was disabled.
Vue v-model with select input - the accepted answer wants me to define it in data and set it to null but that doesn't work when you take a quick glance at my code.
Code:
<select v-model="payload[index]" type="text">
<option v-if="entry.system_role !== null" selected :value="entry.system_role">
{{ entry.system_role }}
</option>
<option v-for="role in entry.roles" :key="entry.id" :value="role">
{{ role }}
</option>
</select>
That is the section with the select and as you can see the v-model is an array which I simply can't set to null. index is from a higher up v-for that renders the amount of <select>.
I tried setting selected to disabled and :value="entry.system_role" to value="" and leaving it empty (but I need the value of this option). Is there anything I can do to make it work? Maybe with a computed or method?

How to have nested select dropdown that will fetch differently for the main list and the dependent list for htmx?

Was requested by maintainer to repost here
Issue
In https://htmx.org/examples/value-select/
I can tell that the make is directly in the html and when it changes, the hx-get is called to fetch a new list of models.
What if I want to have both the make and the model all rely on ajax?
meaning to say
<select name="makes" id="makes" hx-get="/makes" hx-trigger="load">
<option value="none">original</option>
</select>
<select name="models" id="models">
<option value="none">original</option>
</select>
i like to be able to fetch from /makes on load to get the list of makes option
and then somehow I can also fill up the dependent models as well.
I don't mind doing it as two requests. The reason is that in my situation the makes are also dependent on a 3rd party API
I hope I understand what you want, but something like this should work:
<select name="makes" id="makes" hx-get="/makes" hx-trigger="load">
<option value="none">original</option>
</select>
<select name="models" id="models"
hx-get="/models"
hx-trigger="changed from:#makes"
hx-include="#makes">
<option value="none">original</option>
</select>
So you add a trigger to the second drop down that listens for changed events on the #makes drop down and then fires up a request to the /models URL, including the value of the #makes drop down so you know what models to return.
Does that seem like what you want?

Access directive state and populate ngFor

I have settings in a backend exposed via a service. It's very common to wire up widgets over and over to settings, so I created a directive to allow setting the unique name of the setting to attach a widget to:
<dropdown appSetting="uniqueName">
I've got the two way binding working.
Now in settings that represent groups there's an enum that defines the options. I'd like to use the bound setting to populate the ngFor for the children:
<dropdown appSetting="uniqueName" #selector>
<option *ngFor="let option of selector.setting.options">
Obviously that doesn't work. I can't access directive state. Most of the things I tried ended up with an undefined ngForOf or the wonderful ExpressionChangedAfterItHasBeenCheckedError. Is there a clean way to leverage the existing directive to populate the children?
(I've tried a custom *appFor, but couldn't quite get it working)
Better Answer:
Directives have an export ability that allows them to be referenced. Just needed to add:
#Directive({
selector: '[appSetting]',
exportAs: 'appSetting'
})
Then access as:
<dropdown
appSetting="uniqueName" #varId="appSetting"
[(ngModel)]="varId.settingValue">
<option *ngFor="let option of varId.options" [value]="option">{{ option }}</option>
</dropdown>
Original Answer
A simple wrapper component did the job giving access to the state of a setting for any object in the template:
<setting-group #setting
[uniqueName]="foo">
<dropdown
[(ngModel)]="setting.settingValue">
<option *ngFor="let option of setting.options">{{ option }}</option>
</dropdown>
</setting-group>
If there's a way to avoid the one-off wrapper for this, please let me know.

Capybara - how to see if a dropdown element is selected?

My HTML is
<select id="auto_policy_autos_attributes_0_ownership" name="auto_policy[autos_attributes][0][ownership]">
<option value="Owned">Owned</option>
<option value="Financed">Financed</option>
<option value="Leased" selected="selected">Leased</option></select>
and I can select up to
find('select#auto_policy_autos_attributes_0_ownership option[value="Leased"]')
correctly, but how do I see if it has been checked?
I tried
find('select#auto_policy_autos_attributes_0_ownership option[value="Leased" selected="selected"]')
but I get
Selenium::WebDriver::Error::InvalidSelectorError: invalid selector:
An invalid or illegal selector was specified
I had hopes for
'select#auto_policy_autos_attributes_0_ownership option[value="Leased"], selected')).to be
but I get a false positive as
'select#auto_policy_autos_attributes_0_ownership option[value="Owned"], selected')).to be
returns true, even though I have selected Leased with
select 'Leased', from: 'auto_policy_autos_attributes_0_ownership'
which I can see working in the browser.
You can use the be_selected matcher:
expect(#session.find('select#auto_policy_autos_attributes_0_ownership option[value="Leased"]')).to be_selected
One option was
expect(has_select?('auto_policy_autos_attributes_0_ownership', selected: 'Leased')).to be true
This is exactly what the capybara have_select matcher is designed for
expect(page).to have_select('auto_policy_autos_attributes_0_ownership', selected: 'Leased')
which describes what you're checking for -- a specific select element with a specifically selected option, and provides for a nice error message when failure happens.
If you really want to stick with the predicate matcher you could also do
expect(find(:option, 'Leased')).to be_selected
although that option could be in any select on the page unless you used a within block or scoped the find to a specific select.

DOJO: How to validate (required="true") selectOneMenu

How i can validate DOJO selectOneMenu (required="true") here is some dummy code.
<select required="true" missingMessage="Ooops! You forgot your gender!"
name="gender" id="gender" data-dojo-type="dijit/form/?">
<option disabled="true" value="">Select a Gender</option>
<option value="1">Male</option>
<option value="2">Female</option>
</select>
Dojo provide 3 type of combobox :
Select
It is simple combobox like select in HTML with no validation and not provide any search facility inside select options.
ComboBox
It is pure form of combobox and name as ComboBox again it will not provide any default validation but it provide search facility within its options.
FilteringSelect
It is an advance form of select have default facility of validation and search facility. And it also has property to take value as input tag take value in HTML.
In dojo you can also try custom validation which is provided inside dojox library.
I hope it will help you.