AngularJS Cascaded Selects
As a follow up to jQuery Mobile Cascaded Selects using MVC4 and KnockoutJs, I have created this AngularJS Cascaded Selects tutorial that gets it’s data from the Chinook Web API Project. The application uses angular data-binding and the ngOptions attribute to dynamically generate a list of option elements for each of the three HTML select elements.
index.html
<!DOCTYPE HTML>
<html ng-app="ChinookApp">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js"></script>
<script src="libs/angular-resource.min.js"></script>
<script src="app.js" type="text/javascript"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
<link rel="stylesheet" href="app.css">
<title>Angular Cascading Selects</title>
</head>
<body>
<div ng-controller="MainCtrl">
<h2>Angular Cascading Selects</h2>
<div class="span6 body-content">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="inputArtist">Artist</label>
<div class="controls">
<select id="inputArtist"
ng-model="artist.selected"
ng-options="artist.ArtistId as artist.Name for artist in artists"
ng-change="artistChanged(artist.selected)">
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="inputAlbum">Album</label>
<div class="controls">
<select id="inputAlbum"
ng-disabled="artistNotSelected"
ng-model="album.selected"
ng-options="album.AlbumId as album.Title for album in albums"
ng-change="albumChanged(album.selected)">
</select>
</div>
</div>
<div class="control-group">
<label class="control-label" for="inputTrack">Track</label>
<div class="controls">
<select id="inputTrack"
ng-disabled="albumNotSelected"
ng-model="track.selected"
ng-options="track.TrackId as track.Name for track in tracks">
</select>
</div>
</div>
</form>
</div>
</div>
</body>
If your connecting to your REST Web API with a URL that has a port number, such as the built-in Visual Studio Development Server, you will need to escape it with two backslashes:
chinookApp.constant('urlBase', 'http://localhost\\:65374/api/');
app.js
'use strict';
var chinookApp = angular.module('ChinookApp', ['ngResource']);
chinookApp.constant('urlBase', 'https://jimfrenette.com/api/chinook/');
chinookApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
chinookApp.factory('ArtistsService', function($resource, urlBase){
return $resource(urlBase + 'artists', {}, {
query: {method:'GET', isArray:true}
});
});
chinookApp.factory('AlbumsService', function($resource, urlBase){
return $resource(urlBase + 'albums/:artistid', { artistid: '@artistid' }, {
query: {method:'GET', isArray:true}
});
});
chinookApp.factory('TracksService', function($resource, urlBase){
return $resource(urlBase + 'tracks/:albumid', { albumid: '@albumid' }, {
query: {method:'GET', isArray:true}
});
});
chinookApp.controller('MainCtrl', function($scope, ArtistsService, AlbumsService, TracksService) {
$scope.artistNotSelected = true;
$scope.artists = ArtistsService.query({}, function (artists) {
artists.unshift({"ArtistId":0,"Name":"-- Select Artist --"});
$scope.artist = {selected: artists[0].ArtistId};
});
$scope.albumNotSelected = true;
$scope.album = {selected: "0"};
$scope.trackNotSelected = true;
$scope.track = {selected: "0"};
$scope.artistChanged = function(selectedArtistId) {
$scope.artistNotSelected = !selectedArtistId;
if ($scope.artistNotSelected)
{
$scope.album = {};
}
else {
$scope.albums = AlbumsService.query({ artistid: $scope.artist.selected }, function (albums) {
albums.unshift({"AlbumId":0,"Title":"-- Select Album --"});
$scope.album = {selected: albums[0].AlbumId};
$scope.albumNotSelected = true;
$scope.tracks = [];
});
}
};
$scope.albumChanged = function(selectedAlbumId) {
$scope.albumNotSelected = !selectedAlbumId;
if ($scope.albumNotSelected)
{
$scope.track = {};
}
else {
$scope.tracks = TracksService.query({ albumid: $scope.album.selected }, function (tracks) {
tracks.unshift({"TrackId":0,"Name":"-- Select Track --"});
$scope.track = {selected: tracks[0].TrackId};
});
}
};
});