JS:
angular
.module('app', [])
function MainCtrl() {
var ctrl = this;
ctrl.selectionList = [
{ id: 1, name: 'apple'},
{ id: 2, name: 'banana'},
{ id: 3, name: 'grapes'},
{ id: 4, name: 'carrot'}
];
ctrl.selectedThing = ctrl.selectionList[0].name;
}
angular
.module('app', [])
.controller('MainCtrl', MainCtrl);
HTML:
<div class="row">
<div class="col-sm-3 col-xs-12 unit">
<select
ng-model="ctrl.selectedThing"
ng-options="selections.name as selections.name for selections in ctrl.selectionList">
</select>
</div>
</div><!--end of first row-->
So this code creates four different selections.
The problem is that when I choose an option, let's say for example "apples" on one selection, all the other selections become apples too. Is there any way to solve this with ng-options or should I just write the select in HTML?
You definitely want to use ng-options, as that isn't the issue here. The problem you are seeing is most likely because the ng-model on all of your select elements is the same ctrl variable. So when you update one of them, it changes a single variable that is bound to all four dropdowns. You either need to setup up an array for your selected items, or four different instances of a selected variable.
ctrl.selectedThings = [ctrl.selectedList[0].name, '', '', ''];
Then in your view you can do this...
<select
ng-model="ctrl.selectedThings[rowIndex]"
ng-options="selections.name as selections.name for selections in ctrl.selectionList">
</select>
Not the most robust solution if you are going past 4 items, but you should be able to adapt it to be dynamic.
Your code is working fine, can you check and confirm?!
(function ()
{
var app = angular.module("app", []);
function HomeController()
{
var vm = this;
vm.selectionList = [
{ id: 1, name: 'apple'},
{ id: 2, name: 'banana'},
{ id: 3, name: 'grapes'},
{ id: 4, name: 'carrot'}
];
}
app.controller("HomeController", [HomeController]);
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
<meta charset="UTF-8">
<title>Angular JS App</title>
</head>
<body>
<div class="container" ng-controller="HomeController as homeCtrl">
<div class="row">
<div class="col-sm-3 col-xs-12 unit">
<select
ng-model="homeCtrl.selectedThing"
ng-options="selections.name as selections.name for selections in homeCtrl.selectionList">
</select>
<pre>{{homeCtrl.selectedThing}}</pre>
</div>
</div><!--end of first row-->
</div>
</body>
</html>
If you have ng-model="ctrl.selectedThing" for all of your <select> tags, they will all change to the same selection because they're using the same scope property. Think of it like having 4 variables referencing the same data: if you change one, access any of the variables will retrieve the same result.
You need to bind all of your selects to a different property on scope, so ctrl.selectedThing1,2,...n. That's not very scalable, but that would fix your problem.
Related
This is my html code:
<select id="selectFileType" ng-model="instance.fileType" required>
<option ng-repeat="(key, value) in fileTypes" id="key" value="{{key}}">{{key}} ({{value}})</option>
</select>
I am using a map of items to fill the list with information - now I want to pre-select a specific element based on the key but all the solutions I found didn`t work.
E.g. I tried to use the id field to use something like:
document.getElementById("A").selected = true;
Does someone have an idea what I should do?
Thanks and have a nice day
Use the ng-selected directive to set your pre-selected option.
angular.module('myApp', [])
.controller('ctrl', function($scope) {
$scope.vm = {
priceTypes: [{
id: 3,
name: 'pound'
},
{
id: 5,
name: 'Yen'
},
{
id: 6,
name: 'dollar'
}
]
};
//select model value
$scope.localModel = {
priceType: $scope.vm.priceTypes[1]
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div ng-app="myApp" ng-controller="ctrl">
<select ng-model="localModel.priceType">
<option
ng-repeat="item in vm.priceTypes as item"
ng-selected="localModel.priceType.id == item.id"
value="{{item}}"
>{{item.name}}</option>
</select>
<div>
priceType: {{ localModel.priceType }}
</div>
</div>
I am using angularjs ng-options and ng-model directives in my view to set the select option and get notified when dropdown option is selected or changed. I am also adding extra empty option so that user can deselect this and for that I want value in ng-model expression to be undefined. Is there any way to do that ? I tried adding value=="{{undefined}}" but that takes out the empty option totally.
Here is the plunker example where if I select the empty option then data.model should be undefined but here it is coming as null.
https://plnkr.co/edit/d9Jzs4YgqpWHbOxonwa3?p=preview
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example - example-select-ngvalue-production</title>
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="ngvalueSelect">
<div ng-controller="ExampleController">
<form name="myForm">
<label for="ngvalueselect"> ngvalue select: </label>
<select size="6" name="ngvalueselect" ng-model="data.model" multiple>
<option label='' value="{{undefined}}"/>
<option ng-repeat="option in data.availableOptions" ng-value="option.value">{{option.name}}</option>
</select>
</form>
<hr>
<pre>model = {{data.model === undefined | json}}</pre><br/>
</div>
</body>
</html>
Corresponding app.js is
(function(angular) {
'use strict';
angular.module('ngvalueSelect', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.data = {
model: null,
availableOptions: [
{value: 'myString', name: 'string'},
{value: 1, name: 'integer'},
{value: true, name: 'boolean'},
{value: null, name: 'null'},
{value: {prop: 'value'}, name: 'object'},
{value: ['a'], name: 'array'}
]
};
}]);
})(window.angular);
Thanks
There are two issues with your code:
Your dropdown allows multiple select thanks to the multiple attribute. This means that your model stores array of selections. The value you are looking for is one of the elements of the array, but in your code you are comparing undefined to the whole array.
Your additional option should use ng-value instead of value attribute. You don't need to write is as separate option, you can add it to availableOptions object (as {value: undefined, name: ''}).
Here is the updated plunker:
https://plnkr.co/edit/RXUlW6P7DX2wPZOazwe8?p=preview
SUMMARYI have a list of brands and a list of products. I am using an ng-repeat to show the list of brands, and an ng-repeat with a filter to show the list of products within their respective brands. I want each brand and each product to have a button that shows more about that brand/product. All of these buttons should use the same function on the controller.
PROBLEMThe button that shows more about the brand also shows more about each of that brand's products, UNLESS (this is the weird part to me) I click the button of a product within that brand first, in which case it will work correctly.
CODEPlease see the Plunker here, and note that when you click on 'show type' on a brand, it also shows all the types of the products within that brand: http://plnkr.co/edit/gFnq3O3f0YYmBAB6dcwe?p=preview
HTML
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="MyController as vm">
<div ng-repeat="brand in brands">
<h1>
{{brand.name}}
</h1>
<button ng-click="showType(brand)">
Show Brand Type
</button>
<div ng-show="show">
{{brand.type}}
</div>
<div ng-repeat="product in products
| filter:filterProducts(brand.name)">
<h2>
{{product.name}}
</h2>
<button ng-click="showType(product)">
Show Product Type
</button>
<div ng-show="show">
{{product.type}}
</div>
</div>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
JAVASCRIPT
var app = angular.module('myApp', []);
app.controller('MyController', function($scope) {
$scope.brands = [{
name: 'Kewl',
type: 'Cereal'
}, {
name: 'Joku',
type: 'Toy'
}, {
name: 'Loko',
type: 'Couch'
}]
$scope.products = [{
name: 'Kewlio',
type: 'Sugar Cereal',
brand: 'Kewl'
}, {
name: 'Kewliano',
type: 'Healthy Cereal',
brand: 'Kewl'
}, {
name: 'Jokurino',
type: 'Rattle',
brand: 'Joku'
}, {
name: 'Lokonoko',
type: 'Recliner',
brand: 'Loko'
}, {
name: 'Lokoboko',
type: 'Love Seat',
brand: 'Loko'
}]
$scope.showType = function(item) {
this.show = !this.show;
}
$scope.filterProducts = function(brand) {
return function(value) {
if(brand) {
return value.brand === brand;
} else {
return true;
}
}
}
});
IMPORTANT NOTE: I realize I could add an attribute to the object (brand.show) and pass the object into the function, then change that attribute to true/false, but I don't want to do this because in my actual application, the button will show a form that edits the brand/product and submits the info to Firebase, and I don't want the object to have a 'show' attribute on it. I would rather not have to delete the 'show' attribute every time I want to edit the info in Firebase.
ng-repeat directive create own scope, when you do
this.show = !this.show
you create/change show property in current scope, if click brand button - for brand scope, that global for product, and when click in product button - for scope concrete product.
To avoid this, you should create this property before clicking button, for example with ng-init, like
ng-init="show=false;"
on element with `ng-repeat" directive
Sample
var app = angular.module('myApp', []);
app.controller('MyController', function($scope) {
$scope.brands = [{
name: 'Kewl',
type: 'Cereal'
}, {
name: 'Joku',
type: 'Toy'
}, {
name: 'Loko',
type: 'Couch'
}]
$scope.products = [{
name: 'Kewlio',
type: 'Sugar Cereal',
brand: 'Kewl'
}, {
name: 'Kewliano',
type: 'Healthy Cereal',
brand: 'Kewl'
}, {
name: 'Jokurino',
type: 'Rattle',
brand: 'Joku'
}, {
name: 'Lokonoko',
type: 'Recliner',
brand: 'Loko'
}, {
name: 'Lokoboko',
type: 'Love Seat',
brand: 'Loko'
}]
$scope.showType = function(item) {
this.show = !this.show;
}
$scope.filterProducts = function(brand) {
return function(value) {
if (brand) {
return value.brand === brand;
} else {
return true;
}
}
}
});
/* Styles go here */
h1 {
font-family: impact;
}
h2 {
font-family: arial;
color: blue;
margin-bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
<div ng-app="myApp">
<div ng-controller="MyController as vm">
<div ng-repeat="brand in brands" ng-init="show=false">
<h1>
{{brand.name}}
</h1>
<button ng-click="showType(brand)">
Show Brand Type
</button>
<div ng-show="show">
{{brand.type}}
</div>
<div ng-repeat="product in products
| filter:filterProducts(brand.name)" ng-init="show=false">
<h2>
{{product.name}}
</h2>
<button ng-click="showType(product)">
Show Product Type
</button>
<div ng-show="show">
{{product.type}}
</div>
</div>
</div>
</div>
</div>
The easiest fix for this, if you don't mind putting temporary properties in your data is the following changes:
<div ng-show="product.show">
{{product.type}}
</div>
and
<div ng-show="brand.show">
{{brand.type}}
</div>
and then in your controller
$scope.showType = function(item) {
item.show = !item.show;
}
Alternatively, if you don't want to touch the object properties, you can create an $scope.shownTypes array and have your click either push the object into or remove the object from the shown array. THen you can check for the object's existence in the array and show or not show the type appropriately. Let me know if you need a sample of that.
Your show boolean attribute same for whole tree (is in same scope). Using angular directive with child scope scope:true in ng-repeat helps to isolate each show property. I have forked your plunker code:
http://plnkr.co/edit/cMSvyfeCQOnTKG8F4l55?p=preview
I am new to angular
in the following controller i need to access the object store in my html. But it is not working. Any help
(function () {
'use strict';
angular.module('app').controller('BookController', ['$scope', function ($scope) {
$scope.book = {
id: 1,
name: 'Harry Potter',
author: 'J. K. Rowling',
stores: [
{ id: 1, name: 'Barnes & Noble', quantity: 3 },
{ id: 2, name: 'Waterstones', quantity: 2 },
{ id: 3, name: 'Book Depository', quantity: 5 }
]
};
}]);
});
<div ng-controller="BookController">
{{book.stores}}
</div>
You need to first invoke your anonymous function first using () after the final closing bracket and before the final semi-colon so that the last line looks like this: })();.
You should define angular module first and then amend it with the angular component like controller, service , factory, directive, filters, etc.
angular.module('app', [])
then add ng-app="app" on your page.
Markup
<div ng-app="app" ng-controller="BookController">
{{book.stores}}
</div>
Plunkr Here
Update
If suppose you have multiple store inside the stores object, and you want to show them on the html, then for that you could ng-repeat directive. It will repeat each element on html
<div ng-repeat="s in book.stores">
<span>{{s.name}}</span>
<input type="text" ng-model="s.name" />
<input type="numeric" ng-model="s.quantity" />
</div>
Updated Plunkr
On my page I have a dynamic list of musicians (players) whereas a player can be removed and added to the list. Each player shall have multiple instruments which is also a dynamic list, whereas an instrument can be added or removed from a player's instrument list. So we are talking about two nested dynamic lists.
Here is the code and the problem description under it.
jamorg.html:
<!DOCTYPE html>
<html ng-app='jamorgApp'>
<head>
<link rel="stylesheet" type="text/css" href="C:\Users\jazzblue\Documents\Bootstrap\bootstrap-3.3.2-dist\css\bootstrap.min.css" />
<title>Jam Organizer</title>
</head>
<body>
<div ng-controller='JamOrgController as jamOrg'>
<h1>Jam</h1>
<div ng-repeat='player in players'>
<div>
<h3 style="display: inline-block;">player {{$index}}</h3>
<button ng-click="removePlayer($index)">Remove</button>
</div>
<br/>
<div ng-controller='JamOrgPlayerController as jamOrgPlayer'>
<div ng-repeat='instrument in player'>
<span>Instrument: {{instrument.instrument}},</span>
<span>Level: {{instrument.level}}</span>
<button ng-click="remove($index)">Remove</button>
</div>
<button ng-click="addInstrument()">Add Instrument</button>
Instrument: <input ng-model='newInstrument.instrument'>
Level: <input ng-model='newPlayer.level'>
</div>
</div>
</div>
<script type="text/javascript" src="C:\Users\jazzblue\Documents\AngularJS\angular.min.js"></script>
<script type="text/javascript" src="jamorgApp.js"></script>
</body>
</html>
jamorgApp.js
var app = angular.module('jamorgApp', []);
app.controller('JamOrgController', ['$scope', function($scope){
$scope.players = players;
$scope.removePlayer = function(index) {
$scope.players.splice(index, 1);
}
}]);
app.controller('JamOrgPlayerController', ['$scope', function($scope){
$scope.newInstrument = newInstrument;
$scope.remove = function(index) {
$scope.player.splice(index, 1);
}
$scope.addInstrument = function() {
$scope.player.push(newInstrument);
}
}]);
var players = [
[{instrument: 'Guitar', level: 3}, {instrument: 'Keyboard', level: 3}],
[{instrument: 'Bass', level: 4}],
[{instrument: 'Drums', level: 3}]
];
var newInstrument = [
{instrument: 'x', level: 'y'}
]
Here is my problem: the same newInstrument is being added to all the different players lists which is wrong: each player's instrument list should have its own newInstrument.
How should I change it to get the right design?
Thanks!
Where you do:
$scope.addInstrument = function() {
$scope.player.push(newInstrument);
}
Try doing:
$scope.addInstrument = function() {
$scope.player.push(angular.copy(newInstrument));
}
Update:
In your HTML:
<button ng-click="addInstrument(player)">Add Instrument</button>
In your JS:
$scope.addInstrument = function(player) {
player.push(angular.copy(newInstrument));
}
UPDATE
I created a fiddle where you can check some possible modifications to your code. It uses just one controller and fixes the duplicated object issues.
<button ng-click="addInstrument($index)">Add Instrument</button>
Instrument: <input ng-model='newInstrument.instrument'>
Level: <input ng-model='newPlayer.level'>
and your addInstrument function should be like this
$scope.addInstrument = function(index) {
$scope.players[index].push($scope.newInstrument);
}