This kind of controls are useful when your users selection depends on the previous select.
For example:
- continent (Europe, America, Asia, Oceania)
- country (USA, ...)
- state (California, ...)
- etc
The key concepts based on this kind of implementation are:
- $location.search()
- use reloadOnSearch: false in conjunction on $routeProvider.when. It just updates query params without a reload
Code
In bold the relevant blocks.Controller
'use strict';
angular
.module('angularApp', []);
angular.module('angularApp')
.controller('MainCtrl', ['$scope', '$location', 'queryFactory', function ($scope, $location, queryFactory) {
var params = $location.search(); // the current params dict
var initParams = function () {
/* init controllers conf params */
angular.forEach(params, function (value, key) {
if ($scope.conf.search[key]) {
$scope.conf.search[key].selected = value;
}
});
};
/* The model configuration */
$scope.conf = {
initsearch: 'select1', // the master of all selects
search: {
select1: {
values: [], selected: undefined, slave: 'select2', updater: queryFactory.getSelect1
},
select2: {
values: [], selected: undefined, slave: undefined, updater: queryFactory.getSelect2
},
}
};
/* Master select initialization (lookup of options) */ $scope.conf.search[$scope.conf.initsearch].updater($scope.conf.search)
.success(function(data) {
$scope.conf.search[$scope.conf.initsearch].values = data;
});
/* Init $scope.conf.search depending on search params.
* */
initParams();
// not yet available $watchGroup on angularjs 1.2
angular.forEach($scope.conf.search, function (value, key) { // jshint ignore:line
$scope.$watch('conf.search.' + key + '.selected', function(newValue, oldValue) { // jshint ignore:line
var slave = $scope.conf.search[key].slave;
params[key] = newValue;
$location.search(params);
if (newValue) {
if ($scope.conf.search[slave]) {
$scope.conf.search[slave].updater($scope.conf.search)
.success(function(data) {
$scope.conf.search[slave].values = data;
});
}
else {
// slave is undefined
if ($scope.conf.search[key].selected) {
// end of chain, do something
// TODO
}
}
}
else {
// removed selected and values
if ($scope.conf.search[slave]) {
$scope.conf.search[slave].values = [];
if ($scope.conf.search[slave].selected) {
$scope.conf.search[slave].selected = undefined;
}
}
}
});
});
}]);
Template
<!DOCTYPE html>
<html ng-app="angularApp">
<head>
<script data-require="angular.js@*" data-semver="1.2.22" src="https://code.angularjs.org/1.2.22/angular.js"></script>
<link href="style.css" rel="stylesheet" />
<script src="script.js"></script>
</head>
<body>
<div ng-controller="MainCtrl">
<h2>Master select widget example with AngularJS</h2>
Launch in a separate window in order to see the .search() usage: click on the blue button on your top-right of the demo.<br/>
<select ng-model="conf.search.select1.selected" ng-options="item.id as item.title for item in conf.search.select1.values">
<option value="">--</option>
</select>
<select ng-model="conf.search.select2.selected" ng-options="item.id as item.title for item in conf.search.select2.values">
<option value="">--</option>
</select>
</div>
</body>
</html>
Service (performs $http queries)
angular.module('angularApp')
.factory('queryFactory', ['$q', function ($q) {
// Service logic (mock)
// You should put here your $http calls, for a working example see http://davidemoro.blogspot.it/2014/09/angularjs-how-to-test-http-calls.html
// Public API here
return {
getSelect1: function (conf) { // jshint ignore:line
var promise = $q.when([{id: '1', title: '1'}, {id: '2', title: '2'}]);
promise.success = function(fn) {
promise.then(function(response) {
fn(response);
});
return promise;
};
return promise;
},
getSelect2: function (conf) { // jshint ignore:line
var promise;
if (conf['select1'].selected === '1') {
promise = $q.when([{id: '1.1', title: '1.1'}, {id: '1.2', title: '1.2'}]);
} else {
promise = $q.when([{id: '2.1', title: '2.1'}, {id: '2.2', title: '2.2'}]);
}
promise.success = function(fn) {
promise.then(function(response) {
fn(response);
});
return promise;
};
return promise;
}
};
}]);
How to implement $http tests
You can see an example of tests for a service $http-based decoupled from the controller logic:Results
Selecting 1 on the first select you'll get 1.X values on the second one and so on |
Plunkr demo
I have made a Plunkr demo available at this url:If you open the Plunkr link in fullscreen mode you'll see the query params will change for each input. If you copy and paste the intermediate url you'll get still a compiled form.
No comments:
Post a Comment
Note: only a member of this blog may post a comment.