Dynamically preselected dropdowns with angular - angularjs

In javascript, I have two arrays of objects and am trying to create dropdowns in the html using angular.js:
$scope.members=[
{name: "Paul", position: "Vocals"},
{name: "John", position: "Guitar"},
{name: "George", position: "Guitar"},
{name: "Ringo", position: "Drums"}
];
$scope.positions=[
{label: "Guitar"},
{label: "Vocals"},
{label: "Drums"}
];
HTML:
<select>
<option ng-repeat="position in positions">
{{member.position}}
</option>
</select>
The current HTML is taking the member's position and duplicating it 3 times as the only option in the dropdown. For example, upon loading the page, Ringo's position is preselected as "drums" in the dropdown (that's the way it should be). But when clicking on the dropdown,the options for Ringo are "drums" and "drums", and "drums". They should be "drums", "vocals", and "guitar".
Is there a way to have all the options available AND have the correct one preselected on loading? What's the proper directive?

AngularJS has a directive specifically for select controls. Use it instead of ng-repeat
https://docs.angularjs.org/api/ng/directive/ngOptions
working plunkr
var app = angular.module('plunker', []);
app.controller("MyCtrl", function ($scope) {
$scope.members = [
{name: "Paul", position: "Vocals", alive: true},
{name: "John", position: "Guitar", alive: false},
{name: "George", position: "Guitar", alive: false},
{name: "Ringo", position: "Drums", alive: true}
];
$scope.positions = [
{label: "Guitar"},
{label: "Vocals"},
{label: "Drums"}
];
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<script data-require="angular.js#1.3.x" src="https://code.angularjs.org/1.3.9/angular.js" data-semver="1.3.9"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="MyCtrl">
<ul>
<li ng-repeat="member in members">
{{member.name}}
<select ng-options="position.label as position.label for position in positions" ng-model="member.position"></select>
<input type="checkbox" ng-model="member.alive">Alive?</input>
</li>
</ul>
<pre>
{{members | json}}
</pre>
</div>
</body>
</html>

<select ng-model="selectedBeetle" ng-options="member as member.name for member in members"></select>
<select ng-model="selectedBeetle.position" ng-options="position.label for position in positions"></select>

Related

How to assign default value in Dropdownboxlist?

Hi I am developing angularjs application. I tried many ways to set default value for dropdown in Angularjs but I am not able to set default value.
<select ng-change="getModel(b.ID)" ng-model="b.ID" id="brand" ng-options="b.MakeName for b in list">
<option value="1">-- Select a Make --</option>//Not working
</select>
<select ng-change="getStyle(a.ID)" ng-model="a.ID" ng-options="a.ModelName for a in Modellist" id="make" >
<option value="1">-- Select a Model --</option>
</select>//Not working
<select ng-change="getallDetails(c.ID)" id="type" ng-model="c.ID" ng-options="c.BodyStayleName for c in ModelStyle">
<option value="1">-- Select a Type --</option>
</select>//Not working
May I know am i missing here anything? Any help would be appreciated. Thank you.
Use ng-init or set the default value to the model variable inside the controller,
$scope.BrandId = "1";
DEMO
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script>
<script>
angular.module("myapp", [])
.controller("MyController", function($scope) {
$scope.register = {};
$scope.BrandId = "1";
$scope.brands = [{
id: "1",
name: "TOYOTA"
}, {
id: "2",
name: "HONDA"
}, {
id: "3",
name: "MARUTI"
}, {
id: "4",
name: "BMW"
}];
});
</script>
</head>
<body ng-app="myapp">
<div ng-controller="MyController">
<div>
<select ng-init="BrandId=='1'" ng-model="BrandId" ng-options="brand.id as brand.name for brand in brands"></select>
</div>
</div>
</body>
</html>

Show one property of an object with ng-options and select (not array)

I would like to show only my item.name from my object and I donĀ“t know how to do it.
Here is my pen and now the "name" and "age" properties are being shown.
CodePen
<body>
<div ng-controller="Test">
<select ng-model="selectedItem" ng-options="k.name as v for (k,v) in items">
</select>
</div>
</body>
$scope.items has to be an array, then you can loop over items in your ng-options like this:
In your Angular controller
$scope.items = [
{name: 'Michael', age: 29},
{name: 'John', age: 29},
{name: 'Ronald', age: 29}
];
In your HTML
<select ng-model="selectedItem" ng-options="i.name for i in items"></select>
Forked your CodePen here.

Fetching parent and child value from a nested json in angularjs

I'm very much new to angularjs so I'm facing this issue where i have a nested json, and i am using the parent value as a header and the values of the child as checkboxes. Now, when I want to retrieve the value of those checkboxes which have been ticked, i want it in the format of {parent_name:child_name} stored in an array.
I'm using the following sample data taken from this thread.
Data:
parents : [{
name: 'George',
age: 44,
children: [{
name: 'Jack',
age: 16,
isChecked: 'true'
},{
name: 'Amy',
age: 13,
isChecked: 'false'
}]
}, {
name: 'Jimmy',
age: 38,
children: [{
name: 'Max',
age: 7,
isChecked: 'false'
},{
name: 'Lily',
age: 5,
isChecked: 'false'
},{
name: 'Kim',
age: 4,
isChecked: 'true'
}]
}]
And, my current output
looks like this
My HTML code is
<div class="col-md-12 col-xs-12" ng-repeat="parent in parents ">
<div class="form-group">
<label>{{parent.name}}</label>
<div class="input-group" ng-repeat="child in parent.children">
<label><input type="checkbox" ng-checked="child.isChecked=='true'"> {{child.name}}</label>
</div>
<hr>
</div>
Now, in reference to the image, I want to have {George:Jack} and {Jimmy:Kim} in an array, but i can't find a way to achieve that.
EDIT : I forgot to mention another important point, some checkboxes will be pre-selected. As per the data, checkbox for Jack and Kim will already be ticked on-load. I have to fetch the value for the pre-selected values as well as any newly checked checkboxes.
My Plunker code is here.
I hope my question is clear. Thanks in advance!
The proposed solution modifies your original JSON object.
If for some reasons, you have to keep the original JSON object, you should do a copy of it and store it in the controller scope (Angular has functions to do it).
The idea is to add a isChecked attribute in the original JSON object which will be values to false by default and that will be set to true when the checkbox is selected or false when the checkbox is unselected.
That is possible by using the ng-model directive which binds here a html input to a variable in JS side.
Here is the plunker :
http://plnkr.co/edit/EzDp3mMtlnH3t4bIz8e6?p=preview with Angular js 1.5.
js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.parents = [{
name: 'George',
age: 44,
children: [{
name: 'Jack',
age: 16,
isChecked: true;
},{
name: 'Amy',
age: 13
}]
}, {
name: 'Jimmy',
age: 38,
children: [{
name: 'Max',
age: 7
},{
name: 'Lily',
age: 5
},{
name: 'Kim',
age: 4,
isChecked: true;
}]
}]
$scope.submit= function(){
var results = [];
for (var i=0; i< $scope.parents.length; i++){
var parent = $scope.parents[i];
for (var j=0; j< parent.children.length; j++){
var child = parent.children[j];
if (child.isChecked){
results.push(parent.name +":"+ child.name);
}
}
}
//display info
for ( i=0; i< results.length; i++){
console.log(results[i]) ;
}
}
});
html
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.5.x" src="https://code.angularjs.org/1.5.8/angular.js" data-semver="1.5.8"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<div class="col-md-12 col-xs-12" ng-repeat="parent in parents ">
<div class="form-group">
<label>{{parent.name}}</label>
<div class="input-group" ng-repeat="child in parent.children">
<label><input type="checkbox" ng-checked="child.isChecked=='true'" ng-model="child.isChecked">
{{child.name}}</label>
</div>
<hr>
</div>
</div>
<button type="button" ng-click="submit()" class="btn btn-success width-80px">Submit</button>
</body>
</html>
Using the ngChecked directive, you can only mark the checkbox as checked if the expression (here child.checked=='true') is truthy. However, it doesn't affect the value of your variable child.checked.
I recommand you to use instead the ngModel directive which will bind the value of your checkbox with child.checked (or any other variable).
<div class="col-md-12 col-xs-12" ng-repeat="parent in parents ">
<div class="form-group">
<label>{{parent.name}}</label>
<div class="input-group" ng-repeat="child in parent.children">
<label>
<input type="checkbox" ng-model="child.checked">{{child.name}}
</label>
</div>
<hr>
</div>
Since child.checked is not defined at the begining, it will be falsy so the checkbox won't be checked. You can change this behaviour by setting it to true.
Then, to create an array of your results, you can do something like this:
var results = [];
parents.forEach(function (parent) {
parent.children.forEach(function (child) {
if (child.checked) {
var couple = {};
couple[parent.name] = child.name;
results.push(couple);
}
});
});

AngularJS: Count Filtered Items

I am showing subsets of a list if a checkbox is checked. I would like to replace the X next to the checkbox with the count of the list matching the selection criteria. I have a plunker that does everything but count the subset here.
My Controller looks like this:
var app = angular.module('app', []);
app.controller('MainController', function($scope){
$scope.cbMarvel = true;
$scope.cbDCComics = true;
$scope.heroes = [
{
id: 1,
name: 'Iron Man',
fname: 'Tony',
lname: 'Stark',
location: 'Stark Tower',
comic: 'Marvel'
},
{
id: 2,
name: 'Batman',
fname: 'Bruce',
lname: 'Wayne',
location: 'Bat Cave',
comic: 'DC'
},
{
id: 3,
name: 'Superman',
fname: 'Clark',
lname: 'Kent',
location: 'Metroplis',
comic: 'DC'
},
{
id: 1,
name: 'Daredevil',
fname: 'Jack',
lname: 'Murdock',
location: 'Court Room',
comic: 'Marvel'
},
{
id: 5,
name: 'Flash',
fname: 'Barry',
lname: 'Allen',
location: 'Speedline',
comic: 'DC'
},
{
id: 6,
name: 'Hulk',
fname: 'Bruce',
lname: 'Banner',
location: 'Labratory',
comic: 'Marvel'
},
{
id: 7,
name: 'Hawkeye',
fname: 'Clint',
lname: 'Barton',
location: 'Nest',
comic: 'Marvel'
},
{
id: 8,
name: 'Thor',
fname: 'Donald',
lname: 'Blake',
location: 'Asgard',
comic: 'Marvel'
}
];
});
And my view looks like this:
<!DOCTYPE html>
<html ng-app="app">
<head>
<link data-require="bootstrap#*" data-semver="3.2.0" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.css" />
<link data-require="bootstrap-css#*" data-semver="3.2.0" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" />
<script data-require="bootstrap#*" data-semver="3.2.0" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.js"></script>
<script data-require="jquery#2.0.3 current" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script data-require="angular.js#1.2.20" data-semver="1.2.20" src="https://code.angularjs.org/1.2.20/angular.js"></script>
<script data-require="angular-ui-bootstrap#*" data-semver="0.11.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.0.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="MainController">
<fieldset>
<legend>Comments Log</legend>
<div class="row">
<div class="col-md-4">
<input type="checkbox" ng-model="cbMarvel"/> Marvel [X]
</div>
<div class="col-md-4"> </div>
<div class="col-md-4">
<input type="checkbox" ng-model="cbDCComics"/> DC Comics [X]
</div>
</div>
<div class="row"> </div>
<div class="row col-md-10">
<div ng-if="heroes.length == 0"><b>No Heroes Found!</b>
</div>
<div ng-repeat="h in heroes | filter:{comic:'Marvel'}" ng-show="cbMarvel">
{{ h.name}} - {{h.comic}}
</div>
<div ng-repeat="h in heroes | filter:{comic:'DC'}" ng-show="cbDCComics">
{{ h.name}} - {{h.comic}}
</div>
</div>
</fieldset>
</body>
</html>
Assuming your list of people is in data variable and you filter people using query model, the following code will work for you:
Number of visible people: {{(data|filter:query).length}}
Total number of people: {{data.length}}
summary
{{data.length}} - prints total number of people
{{(data|filter:query).length}} - prints filtered number of people
You could set that count in the view model itself while binding the data or just have a method on the scope that returns the count.
app.controller('MainController', function($scope, filterFilter){
....
$scope.getCount = function(strCat){
return filterFilter( $scope.heroes, {comic:strCat}).length;
}
...
});
and use it as:-
Marvel [{{getCount("Marvel")}}]
.....
DC Comics [{{getCount("DC")}}]
Plnkr
If the list is non changing when you are on the page i would suggest finding out the length and binding it to a property in the view model itself, and use it in the view.
//Set your data model
$scope.cbMarvel = {value:true, count:getCount('Marvel')};
$scope.cbDCComics = {value:true, count:getCount('DC')};
and in your view
<input type="checkbox" ng-model="cbMarvel.value"/> Marvel [{{cbMarvel.count}}]
Plnkr2
If your dataset is huge, instead of using filter inside the getCount, use a forEach and populate the count for each type at once.
Infact you do not need a filter at all, it seems inefficient to iterate through the same list using a filter in your case. Your's is a static list so categorize it in the controller itself.
var comics = $scope.comics = {}; //Dictionary of comics
//Create the collection here.
angular.forEach(heroes, function(itm){
if(!comics[itm.comic]){
comics[itm.comic] = {name:itm.comic, value:true, count:1, items:[itm] };
return;
}
comics[itm.comic].count++; //Incr count
comics[itm.comic].items.push(itm); //push specific item
});
and remove all the filters in your view and do:-
<div ng-repeat="h in comics.Marvel.items" ng-show="comics.Marvel.value">
{{ h.name}} - {{h.comic}}
</div>
<div ng-repeat="h in comics.DC.items" ng-show="comics.DC.value">
{{ h.name}} - {{h.comic}}
</div>
Plnk3 - the better one
Possible solution 1: Inline
You could actually save a reference to the filtered results in a variable: h in filtered.marvel = (heroes | filter:{comic:'Marvel'}), which you could use like so: filtered.marvel.length.
See: Plunkr
Possible solution 2: In the controller
You could also move this code to your controller:
$scope.filteredHeroes.marvel = $filter('filter')($scope.heroes, {comic:'Marvel'});
, which you could use by ng-repeat="hero in filteredHeroes.marvel"
and {{filteredHeroes.marvel.length}}
(Don't forget to add $filter as a controller dependency)
See: Plunkr
To find the count objects, I use <scope_obj>.length in the .html template.
Here's my controller:
conciergeControllers.controller('GuestMsgPreviewCtrl', ['$scope', 'GuestMessages',
function($scope, GuestMessages) {
$scope.guests = GuestMessages.query();
}]);
And template (each guest object has a messages attribute that is an array object, so .length returns the number of nested message objects:
<ul ng-repeat="guest in guests">
<li>[[ guest.messages.length ]]</li>
</ul>

ngOptions where selection causes content to change

I am having a hard time with ngOptions in that I need to have a label have multiple values, where selecting a value will determine what is evaluated in the view. For example, if the label is Boy, the value could be he or him. And then depending on the sentence will depend on whether he or him is used.
HTML:
<!DOCTYPE html>
<html ng-app="myTest">
<head>
<script data-require="angular.js#*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="TestController">
<select ng-model="test" ng-options="gen.pick group by gen.gender for gen in gender">
</select>
<p>{{ gender.value }} is a girl</p>
<p>{{ gender.value }} is a boy</p>
</body>
</html>
Code:
angular.module('myTest', []).controller('TestController', function($scope) {
$scope.gender = [
{ pick: 'she', gender: 'female'},
{ pick: 'her', gender: 'female'},
{ pick: 'he', gender: 'male'},
{ pick: 'him', gender: 'male'}
];
})
You could do this with ng-show or ng-if:
<span ng-show="test.gender == 'female'">
<p ng-show="test.pick == 'she'">{{ test.pick }} is a girl</p>
<p ng-show="test.pick == 'her'">{{ test.pick }} hair is pretty</p>
</span>
<p ng-show="test.gender == 'male' && test.pick == 'he'">{{ test.pick }} is a boy</p>
A mapping object could clean it up a little:
$scope.type = {'she': 'girl', 'he': 'boy' };
...
<p ng-if="type[test.pick]">{{test.pick}} is a {{type[test.pick]}}</p>
This example is not dissimilar to j.wittwer's approach, but I used a single object containing all of the relevant data and then used Underscore to find and filter data from that source.
It sounds like you're having a tough time conceptualizing a solution, so I thought it might be helpful for you to see a few approaches at what we think you're trying to get at.
JS (from controller)
$scope.sentenceComponents = [
{ pronoun: 'she', gender: 'girl', sentenceType: 1},
{ pronoun: 'her', gender: 'girl', sentenceType: 2},
{ pronoun: 'he', gender: 'boy', sentenceType: 1},
{ pronoun: 'him', gender: 'boy', sentenceType: 2}
];
$scope.genders = _.uniq(_.pluck($scope.sentenceComponents, 'gender'));
$scope.sentenceTypes = _.uniq(_.pluck($scope.sentenceComponents, 'sentenceType'));
$scope.selectChange = function() {
$scope.selectedComponents = _.findWhere($scope.sentenceComponents, {gender: $scope.selectedGender, sentenceType: $scope.selectedType});
};
$scope.selectedGender = 'girl';
$scope.selectedType = 1;
$scope.selectChange();
HTML
<select ng-model="selectedGender" ng-options="gender for gender in genders" ng-change="selectChange()"></select>
<select ng-model="selectedType" ng-options="sentenceType for sentenceType in sentenceTypes" ng-change="selectChange()"></select>
<p ng-show="selectedComponents.sentenceType == 1">
{{ selectedComponents.pronoun }} is a {{ selectedComponents.gender }}
</p>
<p ng-show="selectedComponents.sentenceType == 2">
The {{ selectedComponents.gender }} took the books from {{selectedComponents.pronoun}}
</p>
Plunker Demo

Resources