How can I avoid the empty value in the ng-select.
My intention is that whenever I have a boolean property in the component set to true - there is only one record in the validFiltersData - then I want the drop down to be selected on it and disabled, so the user cannot select the empty option.
<ng-container *ngFor="let validFilter of validFiltersData; let i = index">
<div *ngIf="validFilter.Values && validFilter.Values.length > 0"
class="filter col-md-4 reportFilter">
<ng-select [items]="validFilter.Values" bindLabel="Text"
[(ngModel)]="validFilter.selectedValue"
[ngClass]="{'input-md': true, 'ng-invalid':
!validFilter.IsValid }">
</ng-select>
</div>
</ng-container>
I managed to do so by using the placeholder property - setting it to the relevant value of the model:
<ng-container *ngFor="let validFilter of validFiltersData; let i = index">
<div *ngIf="validFilter.Values && validFilter.Values.length > 0"
class="filter col-md-4 reportFilter">
<ng-select [items]="validFilter.Values" bindLabel="Text"
placeholder = {{validFilter.DefaultSelectedFilterText}}
[(ngModel)]="validFilter.selectedValue"
[ngClass]="{'input-md': true, 'ng-invalid':
!validFilter.IsValid }">
</ng-select>
</div>
</ng-container>
Related
I'm trying to focus on several elements of my form but the first one, despite being applied, returns an error by console.
This is my template:
<div class="container">
<div class="col-xs-12">
<div class="row">
<h1 class="animal-title">Your selection is : </h1>
</div>
<div class="wrapper">
<form class="first-form" #submit.prevent="onSubmit">
<div class="image-wrapper">
<div class="sel-image">
<div v-on:click="imageSelected = true" v-for="item in items" v-bind:key="item.id">
<label>
<input
type="radio"
name="selectedItem"
ref="item"
:value="item.id"
v-model="itemFormInfo.selectedItem"
#change="onChangeItem($event)"
/>
<img v-if="item.id === 1" src="../../assets/1.png" />
<img v-if="item.id === 2" src="../../assets/2.png" />
<img v-if="item.id === 3" src="../../assets/3.png" />
</label>
<p class="cie-animal-subtitle">{{item.name}}</p>
</div>
</div>
</div>
<div class="form-select">
<div v-show="filteredStock && (imageSelected || itemFormInfo.selectedItem) > 0">
<h1 v-if="this.itemName === 'Phone' || this.itemName === 'Tablet'" for="selectedItem" ref="itemVisible">
Select the brand of your <span>{{this.itemName}}</span> :
</h1>
<h1 v-if="this.itemName === 'PC'" for="selectedBreed" ref="itemVisible">
Select the type of your <span>{{this.itemName}}</span> :
</h1>
<select
ref="brand"
class="form-control"
id="selectedBrand"
v-model="itemFormInfo.selectedBrand"
#change="onChangeBrand($event)">
<option v-for="brand in filteredBrand" v-bind:key="brand.name">{{ brand.name }}</option>
</select>
<div v-show="this.isBrandSelected">
<h1>What are you going to use your
<span>{{itemName}}</span> for ?
</h1>
<input
type="text"
id="componentName"
ref="componentName"
class="form-control fields"
style="text-transform: capitalize"
v-model="itemFormInfo.component"
#keypress="formChange($event)"
/>
<div class="loader-spinner" v-if="loading">
<app-loader/>
</div>
</div>
</div>
</div>
<div class="service-options" v-show="isComponentCompleted">
<div class="from-group">
<h1>
Here are the options for your <span>{{this.itemFormInfo.component}}</span> :
</h1>
<div class="services">
<div class="column-service" v-for="option in options" v-bind:key="option.name">
<div class="service-name">{{option.name}}</div>
<div class="service-price">{{option.price.toString().replace(".", ",")}} </div>
</div>
</div>
and here my first method
onChangeItem(event) {
let item = event.target._value;
this.itemName = this.getItemName(item);
if (this.isItemSelected = true) {
this.isItemSelected = false;
this.isComponentCompleted = false;
this.isLoaderFinished = false;
this.itemFormInfo.name = ""
}
this.$refs.item.focus();
},
in this function that I control my first input, the focus is working but it returns me by console the following error:
"this.$refs.item.focus is not a function at VueComponent.onChangeItem"
I have seen some references to similar cases where they involved the reference in a setTimeout or used the this.$nextTick(() => method but it didn't work in my case.
What am I doing wrong?
How can I focus on the next select with ref brand, once I have chosen the value of the first input?
Thank you all for your time and help in advance
How can I focus on the next select with ref brand, once I have chosen the value of the first input?
You want to put focus on brand but your onChangeItem handler is calling this.$refs.item.focus() (trying to focus item). Seems strange to me...
Reason for the error is you are using ref inside v-for.
Docs: When used on elements/components with v-for, the registered reference will be an Array containing DOM nodes or component instances
So the correct way for accessing item ref will be this.$refs.item[index].focus().
Just be aware that right now v-for refs do not guarantee the same order as your source Array - you can find some workarounds in the issue discussion...
i'm getting an error in the below code saying this is undefined.
<div class="location-list__item" v-for="(value, key) in locations.data">
<div class="location-list__item--text"
:class="{ selected: selected === key }"
#click="() => { this.selected = key; this.manageSurrounding = false }">
<i class="fas fa-compass"></i> {{ value.name }}
<span v-if="value.changed" class="has-text-danger"> Changed</span>
</div>
</div>
However if I change this line:
#click="() => { this.selected = key; this.manageSurrounding = false }"
to this
#click="selected = key"
It works fine, however I need to change manageSurrounding at the same time and I don't want to create a method for such a simple thing.
You can do multiple assignments by using semicolon like the above statement which you have written.
<div class="location-list__item" v-for="(value, key) in locations.data">
<div class="location-list__item--text"
:class="{ selected: selected === key }"
#click="selected = key;manageSurrounding = false"> # Like this
<i class="fas fa-compass"></i> {{ value.name }}
<span v-if="value.changed" class="has-text-danger"> Changed</span>
</div>
</div>
You can use a anonymous function like,
<div onclick="return function()
{ selected = key; manageSurrounding = false }'
</div>
Just create a method and put in the update lines, you are better off on the long run, if your list is changing/reordering/re-rendering often.
It’s an optimization opportunity, so don’t try to force it in just because it seems small. Have a look at this answer: anonymus function in template
I am trying to build a table where rows are items (first v-for), columns are locations (second v-for), cells are item_locations (third -v-for).
If for a certain location the item is present (hence an item_location object) I want to print yes, else I want to print No.
<div v-for="item in items" :key="item.id>
{{item.name}}
<div v-for="location in locations" :key="location.id">
<div v-for="item_location in location.item_locations" :key="item_location.id">
</div>
</div>
</div>
By adding this in the third loop:
<p v-if="item_location.item_id == item.id">Yes</p>
I it correctly prints yes for combination of item/location for which there is an item_location.
What I am unable to do is to print No only for the combinations of item/location for which an item_location object does not exist. To further clarify, item_locations is a joining table.
A little confused on what your asking but Im going to suggest this
Your nested v-for must use the property declared from its parent like so
<div class="table-cell" v-for="location in locations" :key="location.id">
<div v-for="item_location in location.item_locations" :key="item_location.id">
<div v-if="item_location.location_id == location.id ">Yes</div>
<div v-else>No</div>
</div>
</div>
so the nested v-for would be location.item_locations and if your only checking for one condition you can just do a v-else.
I solved this way:
<div v-for="item in items" :key="item.id>
{{item.name}}
<div v-for="location in locations" :key="location.id">
<div>{{filterLocation(item, location)}}</div>
</div>
</div>
filterLocation: function(item, location) {
let value = item.item_locations.filter(item_location => {
return item_location.location_id == location.id;
});
var that = this;
that.item_location_exists = value.length;
},
And in template I can do a conditional as item_location_exists equals to 0 or 1.
In my vue 2.5.17 app I have a select input and text input and I have a create a validation rule that only 1 of them musdt be filled :
<div class="form-row p-3">
<label for="existing_user_list_id" class="col-12 col-sm-4 col-form-label">Select already existing list</label>
<div class="col-12 col-sm-8">
<v-select
v-model="selection_existing_user_list_id"
data-vv-name="selection_existing_user_list_id"
:options="userListsByUserIdArray"
v-validate="''"
id="existing_user_list_id"
name="existing_user_list_id"
class="form-control editable_field"
placeholder="Select existing user list"
v-on:input="onChangeSelectionExistingUserListId($event);"
></v-select>
<span v-show="vueErrorsList.has('existing_user_list_id')" class="text-danger">{{ vueErrorsList.first('existing_user_list_id') }}</span>
</div>
</div>
<div class="form-row p-1 m-1 ml-4">
<strong>OR</strong>
</div>
<div class="form-row p-2`">
<label for="new_user_list_title" class="col-12 col-sm-4 col-form-label">Create a new list</label>
<div class="col-12 col-sm-8">
<input class="form-control" value="" id="new_user_list_title" v-model="new_user_list_title" #change="onChangeBewUserListTitle($event);">
<span v-show="vueErrorsList.has('title')" class="text-danger">{{ vueErrorsList.first('title') }}</span>
</div>
</div>
I found this :
https://baianat.github.io/vee-validate/guide/custom-rules.html#creating-a-custom-rule
But I am confused how to use it in my case. I try :
import { Validator } from 'vee-validate';
Validator.extend('new_user_list_title', {
getMessage: field => 'The ' + field + ' value is not a valid new_user_list_title.',
validate: value => false // for simplicity I try to raise error always
// validate: value => value.length == 0 && selection_existing_user_list_id == null
})
But my custom error is never triggered, even when I set always false,
Which is right way ?
Thanks!
After adding custom rule, you need to use it in component (in v-validate):
<input
class="form-control"
id="new_user_list_title"
v-model="new_user_list_title"
#change="onChangeBewUserListTitle($event);"
v-validate="'new_user_list_title'">
I am building a multiple page app with latest Laravel and latest Vue.js. At the end of this post you will see what I am trying to achieve - which I have done visually. However the user needs to be able to edit the text, assigned user and the date of each item. I have started with the date and as you can see I have the date picker working as well.
Where I am struggling is updating the main model of data in the root so that I can save the changes that the user has made via a HTTP request. Initially the tree's data is loaded in via HTTP as well (example below).
I have built the below using nested components and I have read that two binding has been depreciated for props on components. I know that I need to emit and user events but I'm sure how this would work if the components are nested?
Here is an example of the data that get's loaded via HTTP. Below is a very small example, however this could be much larger
{
"objective":"Test",
"user_id":null,
"by":"08\/09\/2018",
"colour":"#1997c6",
"children":[
{
"objective":"Test",
"user_id":11,
"by":"08\/09\/2018",
"colour":"#d7e3bc",
"children":[]
}, {
"objective":"Test",
"user_id":11,
"by":null,
"colour":"#1997c6",
"children":[]
}
]
}
Here are the components that I have put together so far.
Vue.component('tree-date', {
props: ['date'],
data () {
return {
id: 0
}
},
mounted() {
this.id = uniqueId();
$('#picker-' + this.id).datetimepicker({
format: 'DD/MM/YYYY',
ignoreReadonly: true
});
},
template: `
<div class="date-container" :id="'picker-' + id" data-target-input="nearest" data-toggle="datetimepicker" :data-target="'#picker-' + id">
<div class="row">
<div class="col-2">
<div class="icon">
<i class="fa fa-calendar-alt"></i>
</div>
</div>
<div class="col-10">
<input type="text" class="form-control datetimepicker-input" readonly="readonly" :data-target="'#picker-' + id" v-model="date">
</div>
</div>
</div>`
});
Vue.component('tree-section', {
props: ['data', 'teamUsers', 'first'],
methods: {
test () {
this.$emit('test');
}
},
template: `
<table v-if="data.length != 0">
<tr>
<td :colspan="data.children !== undefined && (data.children.length * 2) > 0 ? data.children.length * 2 : 2">
<div class="node" :class="{'first': first == true}">
<div class="inner">
<tree-date :date="data.by"></tree-date>
<div class="objective">
{{ data.objective }}
</div>
<div class="author" v-if="data.user_id !== null">
{{ teamUsers[data.user_id].first_name }} {{ teamUsers[data.user_id].last_name }}
</div>
<div class="author" v-if="data.user_id === null">
Unassigned
</div>
</div>
</div>
</td>
</tr>
<tr class="lines" v-if="data.children.length > 0">
<td :colspan="data.children.length * 2"><div class="downLine"></div></td>
</tr>
<tr class="lines" v-if="data.children.length > 0">
<td class="rightLine"></td>
<td class="topLine" v-for="index in ((data.children.length * 2) - 2)" :key="index" :class="{'rightLine': index % 2 == 0, 'leftLine': Math.abs(index % 2) == 1}"></td>
<td class="leftLine"></td>
</tr>
<tr v-if="data.children.length > 0">
<td colspan="2" v-for="child in data.children">
<tree-section :data="child" :team-users="teamUsers" :first="false"></tree-section>
</td>
</tr>
</table>
`
});
This all get's called in the view by:
<tree-section :data="data" :team-users="teamUsers" :first="true"></tree-section>
Any help getting data update in the components back into the root will be most helpful.
by default, vue props (if objects or arrays) are being passed by reference- that means that if you change your object on the child component, the original object on the parent component will get changed too.
from vue api:
Note that objects and arrays in JavaScript are passed by reference, so
if the prop is an array or object, mutating the object or array itself
inside the child component will affect parent state.
https://v2.vuejs.org/v2/guide/components-props.html