How to add extra option to v-select after setting :items prop - vuetify.js

I have a v-select, written like this :
<v-select
ref="v_select_folder"
dense
hide-details
v-model="selectedPlanFolder"
label="PlanFolder"
:items="PlannedFolder"
item-text="node.name"
return-object
#change="setFolderNameAndID"
>
The v-select gets the available options/values dropdown from :items, I would like to know how if there is a simple way I can add an extra aditional option , without touching the items prop. Something like :
<v-select
ref="v_select_folder"
dense
hide-details
v-model="selectedPlanFolder"
label="PlanFolder"
:items="PlannedFolder"
item-text="node.name"
return-object
#change="setFolderNameAndID"
>
<option>This is another select value</option>
</v-select>

You can create a new array in place with the spread operator and add an item to it. You may want to add additional properties to the added item depending on how you process your data.
<v-select
ref="v_select_folder"
dense
hide-details
v-model="selectedPlanFolder"
label="PlanFolder"
:items="[...PlannedFolder, { node: { name: 'name' } }]"
item-text="node.name"
return-object
#change="setFolderNameAndID"
>
</v-select>

Related

Quasar WYSIWYG q-editor validation rules and styles

I hava a form with WYSIWYG field and I use Quasar's q-editor element. I want to add validation to that field with rules and styles similar to other fields like q-input, q-select etc.
Sample for q-input validation is:
<q-input v-model="model" label="Name" :rules="[val => !!val || 'Field is required']" />
Result:
This example for required WYSIWYG field doesn't work:
<q-editor v-model="editor" min-height="5rem" :rules="[val => !!val || 'Field is required']" />
There are similar questions here and here (with one posible solution).
Actually Quasar logic is to use q-field wrapper element. Maybe it is a good idea to be added as desctription in q-editor page.
That I do is wrap q-editor in q-field. When q-editor is in template #control on q-field, val for validation val => !!val || 'Field is required' is the content of q-editor. Maybe the reason is that the v-model is same for the two elements.
The problem is when validation failed, then the border of the q-field becomes red, and not of the q-editor. For this problem I use solution from the second link in the question - added custom style to border of q-editor and q-field is borderless.
<q-field ref="fieldRef" v-model="editor" label-slot borderless
:rules="[val => (!!val && val !== '<br>') || 'Field is required']" >
<template #label>Description</template>
<template #control>
<q-editor v-model="editor" min-height="5rem" class="full-width"
:style="fieldRef && fieldRef.hasError ? 'border-color: #C10015' : ''"/>
</template>
</q-field>
Result:
Here is the CodePen example.

How to disable animations for polymer's paper-dropdown-menu element?

I need to disable all animations that happen when opening/closing polymer's paper-dropdown-menu element.
Documentation: https://www.webcomponents.org/element/#polymer/paper-dropdown-menu/elements/paper-dropdown-menu#property-noAnimations
The documentation shows that the element has a noAnimations property that I should be able to set to true to disable all animations, but it's not working for me.
<paper-dropdown-menu
noAnimations="true"
selected="{{selected}}"
attr-for-selected="name"
vertical-offset="60"
>
<paper-listbox slot="dropdown-content" selected="1">
<template is="dom-repeat" items="{{sections}}">
<paper-item name$="{{item}}">{{item}}</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
I expected that setting noAnimations="true" would disable all animations, but it does not. Am I missing something?
Polymer attributes format is always lowercase and separated with dashes; so try:
<paper-dropdown-menu
no-animations="true"
selected="{{selected}}"
attr-for-selected="name"
vertical-offset="60"
>
...
instead:
<paper-dropdown-menu
noAnimations="true"
selected="{{selected}}"
attr-for-selected="name"
vertical-offset="60"
>

change selected option of v-select using vue-test-util

I'm trying to test a component builded with vuetify. For that I'm using vue-test-utils. My goal is to perform a change in the v-select field, and assert hat a mutation is performed. here is my code:
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-layout row wrap>
<v-flex xs6>
<v-subheader>Standard</v-subheader>
</v-flex>
<v-flex xs6>
<v-select
:items="items"
v-model="e1"
label="Select"
single-line
></v-select>
</v-flex>
</v-layout>
</v-container>
</v-app>
</div>
The first test is ok when i set the data:
componentWrapper.setData({items: storesList})
expect(componentWrapper.vm.$data.items).toHaveLength(2)
I now want to change the selected value I try:
componentWrapper.findAll('#option').at(1).setSelected()
And also
componentWrapper.find('el-select')
Can someone help me to retrieve the select and then change the selected value?
Thanks for your support.
Use wrapper.vm.selectItem('foo'). It works for me.
I found this in vuetify v-select tests:
Old: ~~https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/test/unit/components/VSelect/VSelect.spec.js#L533~~
New: https://github.com/vuetifyjs/vuetify/blob/b2abe9fa274feeb0c5033bf12cc48276d4ac5a78/packages/vuetify/test/unit/components/VSelect/VSelect.spec.js#L28
Edit: Updated link.
wrapper.findAll('.v-list__tile__title').at(0).trigger('click')
It works for me.
By this code, first option is selected.
Here is ref.
I used Vuetify v1.5.5.
My solution. It's very equivalent to YounSeon Ahn's response, just the options selector changed. I'm using Vuetify 2.2.11.
// Found the v-select
wrapper.find('[data-testid="mySelect"]').trigger('click');
// Wait for DOM updating after the click
await localVue.nextTick();
// Find all options and select the first. If you are multiple v-select in your form, the class ".menuable__content__active" represents the current opened menu
wrapper.find('.menuable__content__active').findAll('.v-list-item').at(0).trigger('click');
finally got this working for vuetify 1.5. If your v-select looks like this:
<v-select
:items="projectManagers"
:value="selectedProjectManager"
key="UserId"
label="Choose Name"
item-text="FirstName"
item-value="UserId"
id="nameSelect"
#input="(val)=>{this.handleNameChange(val)}"
/>
then do this:
wrapper.findAll('#nameSelect').at(0).trigger('input')
this works, but for some reason if i do at(1) it does not work. Thankfully for my test case the option at position 0 is fine
This is my final solution to test Vuetify VSelect component in cypressjs:
cy.get('#YourVSelectComponentId', { timeout: 20000 }).should('not.have.attr', 'disabled', 'disabled').click({ force: true }); //find v-select, verify it's visible and then click.
cy.get('.menuable__content__active').first().find('.v-list__tile').first().should('be.visible').click(); //find opened dropdown, then find first item in options, then click
I have been struggling with this as well and finally found a way to do it. I'm using Jest and vue-test-utils. Basically, you have to do it with two separate steps. Mark the option as selected and then trigger the change on the select.
The HTML part is:
<select id="groupid" v-model="groupID">
<option value="">-Select group-</option>
<option v-for="g in groupList"
v-bind:value="g.groupId">{{g.groupId}} - {{g.groupName}}
</option>
</select>
And the test is:
it('should populate the subgroup list when a group is selected', () => {
expect(cmp.vm.groupID).toBe('');
expect(cmp.findAll('select#groupid > option').length).toBe(3);
cmp.findAll('select#groupid > option').at(1).element.selected = true;
cmp.find('select#groupid').trigger('change');
expect(cmp.vm.groupID).not.toBe('');
});

Comment out a part of Vue template element

Sometimes it is needed to comment out some element attribute without having to remember it in order to restore it quickly after some tests.
Commenting out whole element is achievable with HTML commenting syntax
<div>
<!-- <h2>Hello</h2> -->
<span>hi</span>
</div>
However this won't work with a single attribute (causes rendering error)
<my-comp id="my_comp_1"
v-model="value"
<!-- :disabled="!isValid" -->
#click="handleClick">
</my-comp>
The best approach I could see and used before was to make a tag backup by copying whole element and settings v-if="false" for it (or comment out whole copied element) and continue to experiment with original one
I don't think you can put an HTML comment inside a component tag, for much the same reason you can't put comments inside an HTML element opening tag. It's not valid markup in either situation. I think the closest you could come would be to place the comment in the quotes:
:disabled="// !isValid"
Which would have the same effect as:
:disabled=""
Depending on whether your component can handle that value being missing, that might fit your needs.
Prefix the attribute value with data- or Wrap with data attribute.
<my-comp id="my_comp_1"
v-model="value"
data-:disabled="!isValid"
data-_click="handleClick"> # `#` could not be used
</my-comp>
or
<my-comp id="my_comp_1"
v-model="value"
data='
:disabled="!isValid"
#click="handleClick">
'>
</my-comp>
I'll with the attribute set to something like data-FIXME.
I got these solutions to work. I thought of solution 1.
Starting code:
<div
v-for="foo in foos"
:key="foo.id"
#click="foo.on = !foo.on /* JavaScript comment. */"
>
<label>
{{ foo.name }} {{foo.on}}
</label>
</div>
The Vue directive HTML attribute that needs to be disabled: #click="foo.on = !foo.on"
How the final div tag will run:
<div
v-for="foo in foos"
:key="foo.id"
>
Solutions 1 and 2 keep the disabled attribute inside its tag. I didn't find a good way to make a "raw string". To keep the attribute in the tag, the outer and inner quotes must be different.
sol. 1: I made a new v-bind attribute (:lang) to put the disabled attribute in.
:lang='en /* #click="foo.on = !foo.on" */'
Sol. 2: Pick a Vue directive. Put the attribute in.
v-for="foo in foos /* #click='foo.on = !foo.on' */"
Solutions 3 and 4 put the attribute outside the tag.
Sol. 3:
<div v-if="false">
#click="foo.on = !foo.on"
</div>
Sol. 4: <!-- #click="foo.on = !foo.on" -->
One way to remove/hide component attributes is to create a custom directive for it.
Let's say you create a directive called v-hide and put it in your component as:
<my-comp v-model="value" #click="handleClick" v-hide :disable='true'></my-comp>
And the output would be:
<my-comp v-model="value" #click="handleClick"></my-comp>
Here is a working example:
Vue.component ('my-component', {
template: `<p> A custom template </p>`
})
Vue.directive('hide', {
inserted: function (el) {
console.log('el before hide', el)
while(el.attributes.length > 0)
el.removeAttribute(el.attributes[0].name);
console.log('el after hide', el)
}
})
new Vue({
el: '#app',
data () {
return {
someValue: 'Hello'
}
}
})
<script src="https://unpkg.com/vue#2.5.3/dist/vue.js"></script>
<div id="app">
<my-component v-model='someValue' v-hide :disable='true'></my-component>
</div>

Using custom polymer element inside paper-datatable-column

I am trying to use < paper-datatable-column > . Inside it I have to use my own polymer element but for some reason its not showing up.
<paper-datatable id="datatable" data="{{users}}" selectable multi-selection selected-items="{{selectedItems}}" on-row-tap="rowTapped">
<paper-datatable-column header="risk" type="Number" property="risk" sortable>
<risk-codes riskcolor={{value}}></risk-codes>
</paper-datatable-column>
</paper-datatable>
Where < risk-codes > is my custom polymer element. Which is defined below :
<template is="dom-if" if={{riskcolor}}>
<div class="fab red">
<paper-ripple class="circle" recenters></paper-ripple>
</div>
</template>
And here is the script of < risk-codes > :
Polymer({
is: 'risk-codes',
properties: {
riskcolor:{
type:Number
}
}
}); //end-polymer
I added < template is="dom bind" > in my custom element and inside it I had put the rest of the code. This did the trick. Strange because i have many custom elements where i am not using "dom-bind" but it works. Maybe because < risk-codes > expects a property from its parent element so it needs to be bound to the DOM. Just a guess, not sure if i am right.

Resources