<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
<title>Fancy Select</title>
<script src="//code.ionicframework.com/nightly/js/ionic.bundle.js"></script>
<
<script src="script.js"></script>
<script src="modal.service.js"></script>
<script src="fancy-select.directive.js"></script>
<link href="//code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body ng-controller="MainController as main">
<ion-header-bar class="bar-positive">
<h1 class="title">Fancy Ionic Select</h1>
</ion-header-bar>
<ion-content>
<ion-list>
<div class="item item-divider">Select single item</div>
<div class="item item-select" fancy-select ng-model="single1" items="selectable" item-label="fname + ' ' +lname">
{{single1.fname || 'Select item'}}
</div>
<div class="item item-divider"> Select select with group by</div>
<div class="item item-select" fancy-select ng-model="single2" items="selectable" item-label="fname+ ' ' +lname" group-by="group">
{{single2.fname || 'Select item'}}
</div>
<div class="item item-divider"> Select select with group by and group label</div>
<div class="item item-select" fancy-select ng-model="single3" items="selectable" item-label="fname+ ' ' +lname" group-by="group" group-label="group+ ' persons'">
{{single3.fname || 'Select item'}}
</div>
<div class="item item-divider">Multiple select</div>
<div class="item item-select" fancy-select ng-model="multi1" multi-select="true" items="selectable" item-label="fname+ ' ' +lname">
{{parseMulti(multi1) || 'Select Items'}}
</div>
<div class="item item-divider"> Multiple select with group by</div>
<div class="item item-select" fancy-select ng-model="multi2" multi-select="true" items="selectable" item-label="fname+ ' ' +lname" group-by="group">
{{parseMulti(multi2) || 'Select Items'}}
</div>
<div class="item item-divider"> Multiple select with group by and group label</div>
<div class="item item-select" fancy-select ng-model="multi3" multi-select="true" items="selectable" item-label="fname+ ' ' +lname" group-by="group" group-label="group+ ' persons'">
{{parseMulti(multi3) || 'Select Items'}}
</div>
</ion-list>
</ion-content>
</body>
</html>
angular.module('app', ['ionic'])
.controller('MainController', function($scope) {
$scope.selectable = [{"fname":"Ghaffar","lname":"Peterman","group":"Good"},{"fname":"Arturo","lname":"Sessa","group":"Good"},{"fname":"Bilal","lname":"Cox","group":"Best"},{"fname":"Serena","lname":"Bradley","group":"Best"},{"fname":"Mario","lname":"Delaura","group":"Best"},{"fname":"Bruce","lname":"Hackman","group":"Good"},{"fname":"Hope","lname":"Barowsky","group":"Best"},{"fname":"Lauris","lname":"Kaa","group":"Better"},{"fname":"Bola","lname":"Obara","group":"Best"},{"fname":"Jamie","lname":"Betts","group":"Good"},{"fname":"Bartley","lname":"Cole","group":"Best"},{"fname":"Wichaya","lname":"Mullins","group":"Good"},{"fname":"Rich","lname":"Seymour","group":"Better"},{"fname":"Denys","lname":"Gallant","group":"Good"},{"fname":"Maurice","lname":"Barrientos","group":"Best"},{"fname":"Jawdat","lname":"Ward","group":"Better"},{"fname":"Sherrie","lname":"Whalley","group":"Better"},{"fname":"Rob","lname":"Gould","group":"Better"},{"fname":"Saowalak","lname":"Hadley","group":"Good"},{"fname":"Marqueal","lname":"Wright","group":"Better"}];
$scope.parseMulti = function(items){
if(items){
return items.map(function(item){ return item.fname + ' ' +item.lname; }).join(', ');
}
};
});
body {
cursor: url('http://ionicframework.com/img/finger.png'), auto;
}
.slide-in-right {
-webkit-transform: translateX(100%);
-moz-transform: translateX(100%);
-ms-transform: translateX(100%);
-o-transform: translateX(100%);
transform: translateX(100%);
}
@media (min-width: 680px){
.slide-in-right.ng-leave-active {
bottom: 20%;
}
}
.slide-in-right.ng-enter,
.slide-in-right > .ng-enter {
-webkit-transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 400ms;
-moz-transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 400ms;
-o-transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 400ms;
transition: all cubic-bezier(0.1, 0.7, 0.1, 1) 400ms;
}
.slide-in-right.ng-enter-active,
.slide-in-right > .ng-enter-active {
-webkit-transform: translateX(0);
-moz-transform: translateX(0);
-ms-transform: translateX(0);
-o-transform: translateX(0);
transform: translateX(0);
}
.slide-in-right.ng-leave,
.slide-in-right > .ng-leave {
-webkit-transition: all ease-in-out 250ms;
-moz-transition: all ease-in-out 250ms;
-o-transition: all ease-in-out 250ms;
transition: all ease-in-out 250ms;
}
.fancy-select.item-select:after{
margin-top: -5px;
width: 0;
height: 0;
border-left: 5px solid;
border-top-color: white;
border-bottom-color: white;
border-top: 5px solid rgba(0, 0, 0, 0);
border-bottom: 5px solid rgba(0, 0, 0, 0);
color: #999;
}
.fancy-select-modal .list{
margin: 0;
}
.fancy-select-modal .list + .list .item:first-child{
margin-top: -2px;
}
function fancySelectDirective($rootScope, $parse, $timeout, genericModalService) {
return {
restrict: 'EA',
require: 'ngModel',
scope: {
'items': '='
},
link: function(scope, element, attrs, ngModelCtrl) {
element.addClass('fancy-select');
// Validate directive attributes.
if (!attrs.items) {
throw(new Error('items requires list over which to iterate.'));
}
if (!attrs.itemLabel ) {
throw(new Error('fancySelect requires a itemLabel expression.'));
}
var multiSelect = scope.$eval(attrs.multiSelect) || false,
closeOnSelection = scope.$eval(attrs.closeOnSelection) || multiSelect ? false : true,
headerText = attrs.headerText || (multiSelect ? 'Select items' : 'Select item'),
templateUrl = attrs.itemsTemplateUrl || 'template/fancy-select/fancy-select.html',
groupBy = attrs.groupBy || '',
groupLabelParser = attrs.groupLabel ? $parse(attrs.groupLabel) : false,
itemLabelParser = $parse(attrs.itemLabel),
modalScope;
function select(){
var viewValue;
if(multiSelect){
viewValue = modalScope.selection.selectable.filter(function (item){return item.selected;});
}else{
viewValue = modalScope.selection.selected;
}
ngModelCtrl.$setViewValue(viewValue);
ngModelCtrl.$render();
}
function showItems(){
modalScope = $rootScope.$new();
modalScope.multiSelect = multiSelect;
modalScope.headerText = headerText;
modalScope.itemLabel = itemLabelParser;
modalScope.closeOnSelection = closeOnSelection;
modalScope.group = groupBy;
modalScope.groupLabel = groupLabelParser;
modalScope.select = select;
modalScope.selection = {
selectable: scope.items,
selected: scope.selected
};
if(multiSelect && typeof modalScope.selection.selected !== 'undefined' && Array.isArray(modalScope.selection.selected)){
modalScope.selection.selectable.forEach(function (item){
delete item.selected;
});
modalScope.selection.selected.forEach(function (item){
var itemIndex = modalScope.selection.selectable.indexOf(item);
if(itemIndex >= 0){
modalScope.selection.selectable[itemIndex].selected = true;
}
});
}
if(closeOnSelection){
var watchable = multiSelect ? 'selection.selectable' : 'selection.selected';
modalScope.$watch(watchable, function (nv, ov){
if(nv !== ov){
select();
$timeout(modalScope.closeModal, 0);
}
}, true);
}
genericModalService.show(templateUrl, modalScope, 'slide-in-right');
}
ngModelCtrl.$render = function() {
scope.selected = ngModelCtrl.$viewValue;
};
element.on('click', showItems);
}
};
}
function fancySelectTemplate ($templateCache) {
$templateCache.put('template/fancy-select/fancy-select.html',
'<ion-modal-view class="fancy-select-modal">' +
' <ion-header-bar align-title="center" class="bar-positive">' +
' <button class="button button-clear button-icon ion-arrow-left-c" ng-click="closeModal()"></button>' +
' <h1 class="title">{{headerText}}</h1>' +
' <button class="button button-clear button-icon ion-checkmark-round" ng-if="!closeOnSelection" ng-click="select(); closeModal();"></button>' +
' </ion-header-bar>' +
' <ion-content>' +
' <div ng-if="group">' +
' <div class="list" ng-if="multiSelect" ng-repeat="(key, value) in selection.selectable | groupBy : group">' +
' <ion-item ng-if="groupLabel" class="item-divider">{{groupLabel(value[0])}}</ion-item>' +
' <ion-checkbox ng-repeat="item in value" ng-model="item.selected">{{itemLabel(item)}}</ion-checkbox>' +
' </div>' +
' <div class="list" ng-if="!multiSelect" ng-repeat="(key, value) in selection.selectable | groupBy : group">' +
' <ion-item ng-if="groupLabel" class="item-divider">{{groupLabel(value[0])}}</ion-item>' +
' <ion-radio ng-repeat="item in value" ng-model="selection.selected" ng-value="item" name="fancy-select">{{itemLabel(item)}}</ion-radio>' +
' </div>' +
' </div>' +
' <div ng-if="!group">' +
' <div class="list">' +
' <ion-checkbox ng-if="multiSelect" ng-repeat="item in selection.selectable" ng-model="item.selected">{{itemLabel(item)}}</ion-checkbox>' +
' <ion-radio ng-if="!multiSelect" ng-repeat="item in selection.selectable" ng-model="selection.selected" ng-value="item" name="fancy-select">{{itemLabel(item)}}</ion-radio>' +
' </div>' +
' </div>' +
' </ion-content>' +
'</ion-modal-view>'
);
}
angular.module('app')
.run(fancySelectTemplate)
.directive('fancySelect', fancySelectDirective);
function ModalService($rootScope, $q, $ionicModal){
function show(templateUrl, scope, animation){
var deferred = $q.defer();
var modalScope = typeof scope !== 'undefined' ? scope : $rootScope.$new();
$ionicModal.fromTemplateUrl(templateUrl, {
scope: modalScope,
animation: animation || 'slide-in-up'
}).then(function(modal) {
modalScope.modal = modal;
modalScope.openModal = function(){
modalScope.modal.show();
};
modalScope.closeModal = function(){
modalScope.modal.hide();
};
modalScope.$on('modal.hidden', function (thisModal){
thisModal.currentScope.$destroy();
thisModal.currentScope.modal.remove();
});
modalScope.modal.show();
deferred.resolve(modalScope);
});
return deferred.promise;
}
return {
show: show
};
}
angular.module('app')
.factory('genericModalService', ModalService);