Dynamic dropdown using ng-repeat in Angular - angularjs

My application gives users the option to choose from several dropdown menus and the third menu should be dynamic depending on the selection from the previous two menus.
I am using ng-repeat and ng-if to set the condition like this
// First dropdown menu
<select ng-model="letter" class = "form-control">
<option ng-repeat= "letter in letters" value = "letter">{{letter}}</option>
</select>
<br>
// second dropdown menu
<select ng-model="number" class = "form-control">
<option ng-repeat = "number in numbers" value = "number">{{number}}</option>
</select>
<br>
// third dropdown menu
<select ng-model="color" class="form-control">
<option ng-repeat="A1_color in A1_colors" ng-if= "letter = A & number = 1" value="{{A1_color}}">{{A1_color}}</option>
</select>
...
<select ng-model="color" class="form-control">
<option ng-repeat="B2_color in B2_colors" ng-if= "letter = B & number = 2" value="{{B2_color}}">{{B2_color}}</option>
</select>
In my controller, I have the lists like this
$scope.letters = {'A', 'B'};
$scope.numbers = {'1', '2'};
$scope.A1_colors = {'red', 'pink'};
$scope.A2_colors = {'blue', 'black'};
$scope.B1_colors = {'yellow', 'orange'};
$scope.B2_colors = {'white', 'black'};
So if the user selects 'A' from the first menu and '2' from the second menu, he should see the options for 'A2_colors' in the third menu. What is the right way to do this?

I think, why to use ng-repeat for <select> tag when angular have another directive ng-options. You should use ng-options instead of ng-repeat. Never the less, you can also use ng-repeat, but it's not good way to do standard coding.
Syntax for ng-options:
<select ng-model="item"
ng-options="item as item for item in collection">
</select>
Your problem will solved by following code:
<div ng-app="MyApp" ng-controller="ctrl">
<select ng-model="letter"
ng-options="letter as letter for letter in letters">
</select>
<select ng-model="number"
ng-options="number as number for number in numbers">
</select>
<select ng-model="color"
ng-options="color as color for color in colors">
</select>
</div>

The "right way" is pretty subjective. Is this just a smaller example of what will be a larger collection of letters, numbers and colors? Here is one way you could approach it where you won't have to create a whole bunch of <select></select> elements that you show or hide.
JS:
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.letters = ['A', 'B'];
$scope.numbers = ['1', '2'];
var colors = {
'A1': ['red', 'pink'],
'A2': ['blue', 'black'],
'B1': ['yellow', 'orange'],
'B2': ['white', 'black']
};
$scope.colorSelection = [];
$scope.setColorSelection = function() {
if ($scope.selectedLetter && $scope.selectedNumber) {
$scope.colorSelection =
colors[$scope.selectedLetter + $scope.selectedNumber];
}
}
});
HTML:
<div ng-app="app" ng-controller="ctrl">
<select ng-model="selectedLetter"
ng-change="setColorSelection()"
ng-options="letter as letter for letter in letters">
</select>
<select ng-model="selectedNumber"
ng-change="setColorSelection()"
ng-options="number as number for number in numbers">
</select>
<select ng-model="selectedColor"
ng-if="colorSelection.length"
ng-options="color as color for color in colorSelection">
</select>
</div>

Related

AngularJS: Show Textfield depending on Select Option

I have a Dropdown with Differnt Options (Numbers). If a number was selected, an amount of textfields should be shown depending on the number that was selected before.
Example:
User selects number = 2
There should be two time a textfield called "name"
<select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
<option value="0">---Please select---</option>
<option value="1">1</option>
<option value="2">2</option>
</select><br>
<div ng-repeat="t in vm.getTimes({{data.singleSelect}}) track by $index">
{{$index}}
<input ng-model="text1" /> <!-- this textfield should be repeated--></div>
Function getTimes in the controller:
vm.getTimes = function (n) {
return new Array(n);
};
I can´t pass vm.getTimes the selected option - why not?
If I write an INT for {{data.singleSelect}} in the function getTimes, it works.
Your getTimes function should be like this.
getTimes = function (n) {
if(n){
return new Array(parseInt(n));
}else{
return 0;
}
}
Why it is not working?
The parameter you passing create array of length initialised using
with the same value.
Because n is string.
You need to parse it to Integer.
Check JavaScript#Array.
Here is the working plunker
You ve a fixed number of options so you can use limitTo
var app = angular.module("app", [])
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
<option value="0">---Please select---</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
<br>
<div ng-repeat="t in [1,2] | limitTo:data.singleSelect track by $index">
{{$index}}
<input ng-model="text1" />
<!-- this textfield should be repeated-->
</div>
</div>
You are trying to create a new array based on the input (that you assume is a number), but you never ensure that this will indeed be one.
For example:
t in getNumber(data.singleSelect * 1) track by $index would solve it, or
$scope.getNumber = function (num) {
return new Array(parseInt(num));
}
would also make your loop function properly.
What you're trying to do:
> new Array("2")
< ["2"]
What you should do:
> new Array(2)
< [undefined × 2]
//don't worry about undefined for now, but this array has 0 and 1 elements.
Here's an updated fiddle with your sample: https://plnkr.co/edit/rPhFnmmKNvHtSirGCYHG?p=preview

How can I make the options of one select depend on another?

Using Angular 2: Essentially, if attr1 is selected in the first dropdown, I want ops1 to populate the list of the second dropdown, and if attr2 is selected in the first dropdown then ops2 and so on. I tried adding a *ngSwitch to the select and option, but then found out you can only add one * to an element. I also want this to update live. In other words, if the user first selects attr1 then switches to attr2 it should update the second dropdown accordingly
<div class="form-group">
<label for="attribute">Attribute</label>
<select class="form-control" id="attribute" [(ngModel)]="model.attribute" name="attribute" required>
<option *ngFor="let attr of attributes" [value]="attr">{{attr}}</option>
</select>
</div>
<div class="form-group">
<label for="operator">Operator</label>
<select class="form-control" id="operator" [(ngModel)]="model.operator" name="operator" required>
<option *ngFor="let op of operators" [value]="op">{{op}}</option>
</select>
</div>
export class MyModelFormComponent {
attributes = ['attr1', 'attr2'... 'attrN'];
ops1 = ['x', 'y', 'z'];
ops2 = ['A', 'B', 'C'];
...
model = new MyModel();
}
I created a dictionary/object of operators as values and the attributes as the keys. The code for operator looks like this:
<select class="form-control" id="attribute" [(ngModel)]="model.attribute" name="attribute" required>
...
<option *ngFor="let op of operators[model.attribute]" [value]="op">{{op}}</option>

Using both <select>'s value AND text for ng-model

I currently have this:
<div>
<label for="market-type">Market Type</label>
<select id="market-type" type="text" ng-model="tradingFee.market_type">
<option value="stock">Stock Market</option>
<option value="otc">OTC Market</option>
</select>
</div>
which assigns the selected option's value to tradingFee.market_type. What I wish is to be able to do this plus assign the selected option's text to tradingFee.market_type_human_friendly_text, for example. Only being able to do one of the assignments is not enough. Is this possible somehow?
You could do this, but not with this syntax. use ng-options so that the ng-model holds both value and display name.
In your controller set array of objects:
$scope.marketType = [{id:"stock", displayName:"Stock Market"}, {id:"otc", displayName:"OTC Market"}];
and
<select id="market-type" type="text"
ng-model="tradingFee.market_type"
ng-options="mt.displayName for mt in marketType track by mt.id">
<option value="">--Select--</option>
</select>
Now the ng-model will have both id as well as value. i.e example:
tradingFee.market_type will be {id:"otc", displayName:"Stock Market"} if you select that specific item from the dropdown. With this you do not have to worry about maintaining 2 separate properties for displayName and id.
angular.module('app', [])
.run(function($rootScope) {
$rootScope.marketType = [{
id: "stock",
displayName: "Stock Market"
}, {
id: "otc",
displayName: "OTC Market"
}];
$rootScope.tradingFee = {
market_type: {
id: 'stock'
}
};
});
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app">
<select id="market-type" type="text" ng-model="tradingFee.market_type" ng-options="mt.displayName for mt in marketType track by mt.id">
<option value="">--Select--</option>
</select>
{{ tradingFee.market_type }}
</div>
You could just use ng-change on your select to fire a custom event handler that sets the secondary value.
<select id="market-type" type="text" ng-model="tradingFee.market_type"
ng-change="updateSecondary()">
<option value="stock">Stock Market</option>
<option value="otc">OTC Market</option>
</select>

Angularjs set value to ng-model

I'm trying to use ng-model to show a series of dropdowns. If I set the top select to empty option then the rest of the dropdowns should be set to the empty option.
<select ng-model="ddl">
<option></option>
<option>1</option>
<option>2</option>
<option>3</option>
</select>
<div ng-show="ddl">
<div ng-show="ddl != null">
<select ng-model="ddl1">
<option></option>
<option>4</option>
<option>5</option>
<option>6</option>
</select>
<div ng-show="ddl1">
<select>
<option></option>
<option>7</option>
<option>8</option>
<option>9</option>
</select>
</div>
</div>
JSFiddle-Link
You could use the ng-change directive to run a funciton in your controller that set's the dropdowns to empty if the top one is empty.
https://docs.angularjs.org/api/ng/directive/ngChange#!
something like
$scope.reset = function() {
if($scope.ddl === "") {
$scope.ddl1 = ""; $scope.ddl2 = "";
}
}

Selected for select option menu if condition is met in AngularJS

<select ng-model="item.value" ng-options="item.name for item in items">
</select>
The above will populate select option in AngularJS, but how can I add selected if my condition is met?
I want to do something like this:
<select ng-model="item.value" ng-options="item.name for item in items" if="item.name == someValueToCheckAgainst" selected endif>
</select>
Obviously the above is wrong, but I was trying to search for this to see if it is possible to do.
This is items
var items = [ 'a', 'b', 'c' ];
var someValueToCheckAgainst = 'b';
so my menu should be like this
<select ng-model="item.value">
<option value="a">a</option>
<option value="b" selected>a</option>
<option value="c">a</option>
</select>
Just figured this out
<select ng-model="form.model">
<option ng-selected="{{item == valueToCheckAgainst}}"
ng-repeat="item in items"
value="{{item}}">
{{item}}
</option>
</select>
For me this statement makes no sense.
<select ng-model="item.value" ng-options="item.name for item in items"> </select>
ng-model is current value (bound model). If your 'item' looks like ’{ value, name }' than you should define your 'select' as
<select ng-model="someValueToCheckAgainst" ng-options="item.value as item.name for item in items"> </select>
The selected option is defined by the value of the ng-model attribute. For further information you can take a look at the official documentation https://docs.angularjs.org/api/ng/directive/select.
I recommend to use ng-option directive instead of ng-repeat for select boxes, beacuse ng-option is specifically created for select box and handles options in best way. And how we can set a default or conditional option value selected in ng-option directive is using ng-init directive with it like this:
<select ng-model="item.value"
ng-options="item.name for item in items"
ng-init="condition ? item.value = items[opt index] : item.value = items[0]">
</select>

Resources