Hello i'm using vuejs and i need your help to get the best practice to do this:
langs : is an object of languages :
langs: {'1':'fr', '2':'en', '3':'ar'},
has_lang : equal to 1 for the case which i need enter a value for each lang
and equal to 0 for case which i need only enter one value for all languages
What i do now :
<md-layout md-gutter>
<md-input-container v-if="has_langs" v-for="lang in langs">
<label>#{{ attribute.attribute }} #{{ lang }}</label>
<md-input v-model="attValues"></md-input>
</md-input-container>
<md-input-container v-if="has_langs == 0">
<label>#{{ attribute.attribute }} #{{ lang }}</label>
<md-input v-model="inputa"></md-input>
</md-input-container>
</md-layout>
What i need is not duplicate the input * two times
this input * :
<md-input-container>
<label>#{{ attribute.attribute }} #{{ lang }}</label>
<md-input v-model="inputa"></md-input>
</md-input-container>
There is a way to set v-for and v-if in the same element or something else that can do this?
You can't really use v-if and v-for on the same element. Best to put the v-if on a parent element.
You can move all checks for has_langs and langs to code.
computed: {
__langs(){
return this.has_langs === 1? this.langs : {'0': 'Params for all'};
}
},
methods: {
manipulateWithLangs(){
if (this.has_langs === 1){
//do
} else {
// do something else
}
}
}
<md-layout md-gutter>
<md-input-container v-for="lang in __langs">
<label>#{{ attribute.attribute }} #{{ lang }}</label>
<md-input v-model="attValues"></md-input>
</md-input-container>
</md-layout>
You could do the v-if with a v-else on the md-layout the component level and get the result you want.
<md-layout v-if="has_langs" md-gutter>
<md-input-container v-for="lang in langs">
...
</md-input-container>
</md-layout>
<md-layout v-else md-gutter>
<md-input-container>
...
</md-input-container>
</md-layout>
Besides the option to create an additional filtered computed (effectively eliminating the need to use v-for and v-if on the same element), you also have a template level way of dealing with such edge-cases: the tag.
The tag allows you to use arbitrary template logic without actually rendering an extra element. Just remember that, because it doesn't render any element, you have to place the keys from the v-for on the actual elements, like this:
<template v-for="(guide, index) in guides"> <article v-if="isGuideVisible(guide)"
:key="index"
class="post-item post-guide"
:class="[guide.categories.toString().replace(/,/g, ' ')]"><header>
<h1 v-text="guide.title.rendered" /></header>
Related
UPDATED
Creating user input popup form, in one field trying to do autocomplete, with THIS solution.
I guess the auto-complete is working fairly fine, the issue is the options not coming below the input box.
Code:
<div>
<div class="modal-header">
</div>
<div class="modal-body">
<form novalidate [formGroup]="myform">
<div class="form-floating form-group">
<input type="text" class="form-control" id="fltName" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
<label for="fltName">Name</label>
<mat-autocomplete autoActiveFirstOption #emp="matAutocomplete" class="form-control">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option">
{{option}}
</mat-option>
<mat-autocomplete>
</div>
Question:
1. The options box should display, only if there 2 or less matches?
2. return emp names options by inserting emp_id?
How can I setup option such as {name:xyz, emp_id:123, emp_no:333}, and if I text any value should give name as option like if I write 33 should bring option xyz.
Question 1: The options box should display, only if there 2 or less matches
For this you need to apply the ng-container (To avoid rendering the option box) directive and apply the length condition over there according to your requirement.
<mat-autocomplete #auto="matAutocomplete">
<ng-container *ngIf="filteredOptions && (filteredOptions | async)?.length <= 2">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option" >
{{option.name}} //this is the value you always want to display
</mat-option>
</ng-container>
</mat-autocomplete>
Question 2: return emp names options by inserting emp_id?
The second part can be achieved by applying filter on the required fields, i.e.
private _filter(value: string): string[] {
if(value && value !== ""){
const filterValue = value.toLowerCase();
return this.options.filter(option => option.name.toLowerCase().includes(filterValue) || option.emp_no.toString().startsWith(filterValue));
} else {
return [];
}
}
apart from this you need to fix the pipe part as well, you have to pass the control value in RxJs startWith operator like,
this.filteredOptions = this.myControl.valueChanges
.pipe(
startWith(this.myControl.value),
map(value => this._filter(value))
);
Note: you can access the working solution here
Is it possible to use a checked state of checkbox to add a class to parent div? If not, how to do it? Here is the code:
<div
class="checkbox-container"
v-for="item in items"
:key="item.id"
:class="{'checked': checkbox.checked}" // I wanna do something like that
>
<input type="checkbox" :id="item.id" :value="item.value" v-model="checkedItems">
<label :for="item.id">{{ item.text }}</label>
</div>
Just use the value from v-model
:class="{'checked': checkedItems.includes(item.value) }"
trying to use md-autocomplete inside a custom directory.
I wanted the field to be required based on two conditions. One which is initialized(cond1) and one that changes(cond2)
I've tried to do it like this:
required="{{ cond1 && !cond2 }}"
But for some reason the md-autocomplete always becomes required, even if cond1 is initially undefined or false. It also doesn't respond to changes done to the value of cond2.
The validator also doesn't check if the selected-item has been set. It just checks if there is text in the field.
ng-required doesn't seem do anything.
Any ideas how i can make this work?
EDIT:
Here is my directive's .html
<div ng-form="dummyForm">
<md-autocomplete
md-input-name="{{ctrl.fieldName}}"
md-selected-item="ctrl.dummyItem"
md-selected-item-change="ctrl.setSelectedItem()"
md-search-text="ctrl.searchText"
md-items="item in ctrl.querySearch(ctrl.searchText)"
md-item-text="item.display || item"
md-min-length="0"
placeholder="{{ ctrl.placeholder }}"
ng-disabled="ctrl.selectAll || ctrl.isDisabled"
required="{{ ctrl.isRequired && !ctrl.selectAll }}">
<md-item-template>
<span>{{ item.display || item }}</span>
</md-item-template>
<md-not-found>
No results.
</md-not-found>
</md-autocomplete>
</div>
<div class="label-wrapper">
<label
class="checkbox-label"
ng-if="ctrl.selectAll !== null">
<input
type="checkbox"
ng-model="ctrl.selectAll"
ng-change="ctrl.checkSelectAll()">
{{ ctrl.checkboxName ? ctrl.checkboxName : 'Select all' }}
</label>
</div>
It is basically just a custom input field that lets the user either select a value from the list OR click the checkbox to "select all" items. When the checkbox is selected, i don't want the md-autocomplete field to be required anymore.
It does work fine with ng-required as you can see in this demo plnkr.
View
<form name="myForm">
<md-autocomplete
md-autoselect=true
placeholder="What is your favorite place?"
md-item-text="item.display"
md-items="item in ctrl.items"
md-menu-class="autocomplete-custom-template"
md-min-length="2"
md-delay="ctrl.throttle"
md-search-text="ctrl.searchText"
md-search-text-change="ctrl.searchTextChange(ctrl.searchText)"
md-select-on-match=true
md-match-case-insensitive=true
md-selected-item-change="ctrl.selectedItemChange(item)"
ng-required="ctrl.cond1 && !ctrl.cond2"
md-selected-item="ctrl.selectedItem">
{{ myForm.$error }}
<div>
<md-button type="submit">Submit</md-button>
</div>
</form>
AngularJS controller
myApp.controller('MyCtrl', function ($scope) {
var vm = this;
this.cond1 = true;
this.cond2 = false;
});
I have an HTML for select tag, with this code :
<div ng-controller="Models">
<select ng-model="myModel" ng-options="Model.name for Model in Models" class="form-control"></select>
{{ {selected_Model:myModel.name} }} {{ {selected_Model:myModel.id} }}
</div>
and I want it to show only myModel.id==1.
how can I do it ?
I think this question needs a bit more of an explanation.
Do you mean you want to display a select for each model in models however only if the model.id ==1?
You can do this with a filter, while the models are being written to the page in your select box this filter checks if they have an .id == 1 and if TRUE then allows it to be written into the select.
I would imagine however that this means you'll only have 1 item in your select box as duplicate id's in objects are bad news bears.
angular.module('YOURAPPNAME', [])
.filter('myModelFilter', function() {
return function(myModel) {
if (myModel.id == 1) {
return myModel;
}
};
})
<div ng-controller="Models">
<select ng-model="myModel" ng-options="Model.name for Model in Models | myModelFilter" class="form-control"></select>
{{ {selected_Model:myModel.name} }} {{ {selected_Model:myModel.id} }}
</div>
EDIT: P.s.
Calling a controller and objects in your controllers "Model" and "Models" is confusing, I'd recommend choosing a different naming convention as AngularJS is an MVWhatever framework the term "Model" has a very different meaning to what you're using it for.
You could this on HTML side itself by using filter with strict checking true like ng-options="Model.name for Model in Models | filter: {id: 1}: true"
Markup
<div ng-controller="Models">
<select ng-model="myModel" class="form-control"
ng-options="Model.name for Model in Models | filter: {id: 1}: true" >
</select>
{{ {selected_Model:myModel.name} }} {{ {selected_Model:myModel.id} }}
</div>
Here is my view for a list.
back...
<ul>
<input type="text" ng-model="search">
<li ng-repeat="item in items | filter:search | orderBy:'date'">
{{ item.ID }} - {{ item.heading }} - {{ item.date | date:"dd.MM.yy" }}
<button ng-click="deleteItem(item.ID)">del</button>
</li>
<form>
<input type="text" ng-model="itemName">
<input type="date" min="{{ date }}" max="{{ maxDate }}" value="{{ date }}" ng-model="itemDate">
<button ng-click="addItem()">add</button>
</form>
</ul>
On click my contoller adds a new item to the view, which works fine. Now i want to animate only the new item with css3. Therefore the new item needs a class. How can i achieve this with angular?
This should assign class the-class to the last element of the list dynamically:
<li ng-class="{'the-class': $last}" ng-repeat="item in items | filter:search | orderBy:'date'">
{{ item.ID }} - {{ item.heading }} - {{ item.date | date:"dd.MM.yy" }}
<button ng-click="deleteItem(item.ID)">del</button>
</li>
If you're using Angular 1.1.5, you can use ngAnimate enter event instead which is precisely designed for this kind of situation.
Have a look at http://www.nganimate.org/ and http://code.angularjs.org/1.1.5/docs/api/ng.directive:ngAnimate
If you use a function to add an Item, you could also set a variable to know which Id is the last inserted while adding the item to the list
First, you can see what I did here http://jsfiddle.net/DotDotDot/Eb2kR/
I just created a lastInsertedId variable, which I use to add a class in the ng-repeat :
<span ng-class='{lastinserted: item.ID==lastInsertedId}'>{{ item.ID }} - {{ item.heading }} - {{ item.date | date:"dd.MM.yy" }}</span>
I had no idea how you implemented you addItem method and what are your IDs, so I created my own method and I assumed your IDs are unique numbers, but it could work with anything (hoping you can find a unique set of data)
$scope.addItem=function(){
var dd=new Date($scope.itemDate);
$scope.items.push( {"ID":$scope.items.length+1, "heading":$scope.itemName, "date":dd.getTime()});
$scope.lastInsertedId=$scope.items.length;
}
I change the last inserted id, which will apply the selected class to the item
You could also unset the lastInsertedId value in the delItem() method
If you have a more difficult logic (here I assumed you had unique IDs) you can also use a function in the ng-class. Here, on my example it wouldn't be hard to code :
$scope.amITheOne=function(item){
return item.ID==$scope.lastInsertedId;
}
then
<span ng-class='{lastinserted: amITheOne(item)}'>
It doesn't change much with a simple logic, but you could totally have a logic based on the ID, the name and the date for example
Have fun