checkbox/radio/toggle updates

This commit is contained in:
Adam Bradley
2014-01-21 16:51:25 -06:00
parent c21ef207ef
commit 73cad15ed2
11 changed files with 330 additions and 178 deletions

View File

@@ -1144,38 +1144,29 @@ angular.module('ionic.ui.checkbox', [])
restrict: 'E',
replace: true,
require: '?ngModel',
scope: {},
scope: {
ngModel: '=',
ngValue: '=',
ngChecked: '=',
ngChange: '&'
},
transclude: true,
template: '<li class="item item-checkbox">\
<label class="checkbox">\
<input type="checkbox">\
</label>\
<div class="item-content" ng-transclude>\
</div>\
</li>',
link: function($scope, $element, $attr, ngModel) {
var checkbox;
template: '<div class="item item-checkbox">' +
'<label class="checkbox">' +
'<input type="checkbox" ng-model="ngModel" ng-value="ngValue" ng-change="ngChange()">' +
'</label>' +
'<div class="item-content" ng-transclude></div>' +
'</div>',
if(!ngModel) { return; }
checkbox = angular.element($element[0].querySelector('input[type="checkbox"]'));
if(!checkbox.length) { return; }
checkbox.bind('change', function(e) {
ngModel.$setViewValue(checkbox[0].checked);
$scope.$apply(function() {
e.alreadyHandled = true;
});
});
if(ngModel) {
ngModel.$render = function() {
checkbox[0].checked = ngModel.$viewValue;
};
}
compile: function(element, attr) {
var input = element.find('input');
if(attr.name) input.attr('name', attr.name);
if(attr.ngChecked) input.attr('ng-checked', 'ngChecked');
if(attr.ngTrueValue) input.attr('ng-true-value', attr.ngTrueValue);
if(attr.ngFalseValue) input.attr('ng-false-value', attr.ngFalseValue);
}
};
});
@@ -1569,43 +1560,22 @@ angular.module('ionic.ui.radio', [])
replace: true,
require: '?ngModel',
scope: {
value: '@'
ngModel: '=',
ngValue: '=',
ngChange: '&',
icon: '@'
},
transclude: true,
template: '<label class="item item-radio">\
<input type="radio" name="radio-group">\
<div class="item-content" ng-transclude>\
</div>\
<i class="radio-icon icon ion-checkmark"></i>\
</label>',
template: '<label class="item item-radio">' +
'<input type="radio" name="radio-group"' +
' ng-model="ngModel" ng-value="ngValue" ng-change="ngChange()">' +
'<div class="item-content" ng-transclude></div>' +
'<i class="radio-icon icon ion-checkmark"></i>' +
'</label>',
link: function($scope, $element, $attr, ngModel) {
var radio;
if(!ngModel) { return; }
radio = $element.children().eq(0);
if(!radio.length) { return; }
if(ngModel) {
radio.bind('click', function(e) {
console.log('RADIO CLICK');
$scope.$apply(function() {
ngModel.$setViewValue($scope.$eval($attr.ngValue));
});
e.alreadyHandled = true;
});
ngModel.$render = function() {
var val = $scope.$eval($attr.ngValue);
if(val === ngModel.$viewValue) {
radio.attr('checked', 'checked');
} else {
radio.removeAttr('checked');
}
};
}
compile: function(element, attr) {
if(attr.name) element.find('input').attr('name', attr.name);
if(attr.icon) element.find('i').removeClass('ion-checkmark').addClass(attr.icon);
}
};
})
@@ -2419,38 +2389,58 @@ angular.module('ionic.ui.toggle', [])
// The Toggle directive is a toggle switch that can be tapped to change
// its value
.directive('toggle', function() {
return {
restrict: 'E',
replace: true,
require: '?ngModel',
scope: {},
template: '<div ng-click="toggleIt($event)" class="toggle" skip-tap-poly><input type="checkbox"><div class="track"><div class="handle"></div></div></div>',
scope: {
ngModel: '=',
ngValue: '=',
ngChecked: '=',
ngChange: '&'
},
transclude: true,
template: '<div class="item item-toggle">' +
'<div ng-transclude></div>' +
'<label class="toggle">' +
'<input type="checkbox" ng-model="ngModel" ng-value="ngValue" ng-change="ngChange()">' +
'<div class="track">' +
'<div class="handle"></div>' +
'</div>' +
'</label>' +
'</div>',
link: function($scope, $element, $attr, ngModel) {
var checkbox, handle;
compile: function(element, attr) {
var input = element.find('input');
if(attr.name) input.attr('name', attr.name);
if(attr.ngChecked) input.attr('ng-checked', 'ngChecked');
if(attr.ngTrueValue) input.attr('ng-true-value', attr.ngTrueValue);
if(attr.ngFalseValue) input.attr('ng-false-value', attr.ngFalseValue);
if(!ngModel) { return; }
// return function link($scope, $element, $attr, ngModel) {
// var el, checkbox, track, handle;
checkbox = $element.children().eq(0);
handle = $element.children().eq(1);
// el = $element[0].getElementsByTagName('label')[0];
// checkbox = el.children[0];
// track = el.children[1];
// handle = track.children[0];
if(!checkbox.length || !handle.length) { return; }
// $scope.toggle = new ionic.views.Toggle({
// el: el,
// track: track,
// checkbox: checkbox,
// handle: handle
// });
$scope.toggle = new ionic.views.Toggle({
el: $element[0],
checkbox: checkbox[0],
handle: handle[0]
});
// ionic.on('drag', function(e) {
// console.log('drag');
// $scope.toggle.drag(e);
// }, handle);
$scope.toggleIt = function(e) {
$scope.toggle.tap(e);
ngModel.$setViewValue(checkbox[0].checked);
};
ngModel.$render = function() {
$scope.toggle.val(ngModel.$viewValue);
};
// }
}
};
});

9
dist/js/ionic.js vendored
View File

@@ -1916,7 +1916,7 @@ window.ionic = {
});
} else if(ele.type === "checkbox") {
ele.checked = !ele.checked;
ionic.trigger('change', {
ionic.trigger('click', {
target: ele
});
} else if(ele.type === "submit" || ele.type === "button") {
@@ -5814,6 +5814,7 @@ ionic.views.TabBar = ionic.views.View.inherit({
initialize: function(opts) {
this.el = opts.el;
this.checkbox = opts.checkbox;
this.track = opts.track;
this.handle = opts.handle;
this.openPercent = -1;
},
@@ -5825,8 +5826,8 @@ ionic.views.TabBar = ionic.views.View.inherit({
},
drag: function(e) {
var slidePageLeft = this.checkbox.offsetLeft + (this.handle.offsetWidth / 2);
var slidePageRight = this.checkbox.offsetLeft + this.checkbox.offsetWidth - (this.handle.offsetWidth / 2);
var slidePageLeft = this.track.offsetLeft + (this.handle.offsetWidth / 2);
var slidePageRight = this.track.offsetLeft + this.track.offsetWidth - (this.handle.offsetWidth / 2);
if(e.pageX >= slidePageRight - 4) {
this.val(true);
@@ -5847,7 +5848,7 @@ ionic.views.TabBar = ionic.views.View.inherit({
} else if(openPercent === 100) {
this.val(true);
} else {
var openPixel = Math.round( (openPercent / 100) * this.checkbox.offsetWidth - (this.handle.offsetWidth) );
var openPixel = Math.round( (openPercent / 100) * this.track.offsetWidth - (this.handle.offsetWidth) );
openPixel = (openPixel < 1 ? 0 : openPixel);
this.handle.style.webkitTransform = 'translate3d(' + openPixel + 'px,0,0)';
}

View File

File diff suppressed because one or more lines are too long

View File

@@ -9,38 +9,29 @@ angular.module('ionic.ui.checkbox', [])
restrict: 'E',
replace: true,
require: '?ngModel',
scope: {},
scope: {
ngModel: '=',
ngValue: '=',
ngChecked: '=',
ngChange: '&'
},
transclude: true,
template: '<li class="item item-checkbox">\
<label class="checkbox">\
<input type="checkbox">\
</label>\
<div class="item-content" ng-transclude>\
</div>\
</li>',
link: function($scope, $element, $attr, ngModel) {
var checkbox;
template: '<div class="item item-checkbox">' +
'<label class="checkbox">' +
'<input type="checkbox" ng-model="ngModel" ng-value="ngValue" ng-change="ngChange()">' +
'</label>' +
'<div class="item-content" ng-transclude></div>' +
'</div>',
if(!ngModel) { return; }
checkbox = angular.element($element[0].querySelector('input[type="checkbox"]'));
if(!checkbox.length) { return; }
checkbox.bind('change', function(e) {
ngModel.$setViewValue(checkbox[0].checked);
$scope.$apply(function() {
e.alreadyHandled = true;
});
});
if(ngModel) {
ngModel.$render = function() {
checkbox[0].checked = ngModel.$viewValue;
};
}
compile: function(element, attr) {
var input = element.find('input');
if(attr.name) input.attr('name', attr.name);
if(attr.ngChecked) input.attr('ng-checked', 'ngChecked');
if(attr.ngTrueValue) input.attr('ng-true-value', attr.ngTrueValue);
if(attr.ngFalseValue) input.attr('ng-false-value', attr.ngFalseValue);
}
};
});

View File

@@ -11,43 +11,22 @@ angular.module('ionic.ui.radio', [])
replace: true,
require: '?ngModel',
scope: {
value: '@'
ngModel: '=',
ngValue: '=',
ngChange: '&',
icon: '@'
},
transclude: true,
template: '<label class="item item-radio">\
<input type="radio" name="radio-group">\
<div class="item-content" ng-transclude>\
</div>\
<i class="radio-icon icon ion-checkmark"></i>\
</label>',
template: '<label class="item item-radio">' +
'<input type="radio" name="radio-group"' +
' ng-model="ngModel" ng-value="ngValue" ng-change="ngChange()">' +
'<div class="item-content" ng-transclude></div>' +
'<i class="radio-icon icon ion-checkmark"></i>' +
'</label>',
link: function($scope, $element, $attr, ngModel) {
var radio;
if(!ngModel) { return; }
radio = $element.children().eq(0);
if(!radio.length) { return; }
if(ngModel) {
radio.bind('click', function(e) {
console.log('RADIO CLICK');
$scope.$apply(function() {
ngModel.$setViewValue($scope.$eval($attr.ngValue));
});
e.alreadyHandled = true;
});
ngModel.$render = function() {
var val = $scope.$eval($attr.ngValue);
if(val === ngModel.$viewValue) {
radio.attr('checked', 'checked');
} else {
radio.removeAttr('checked');
}
};
}
compile: function(element, attr) {
if(attr.name) element.find('input').attr('name', attr.name);
if(attr.icon) element.find('i').removeClass('ion-checkmark').addClass(attr.icon);
}
};
})

View File

@@ -6,38 +6,58 @@ angular.module('ionic.ui.toggle', [])
// The Toggle directive is a toggle switch that can be tapped to change
// its value
.directive('toggle', function() {
return {
restrict: 'E',
replace: true,
require: '?ngModel',
scope: {},
template: '<div ng-click="toggleIt($event)" class="toggle" skip-tap-poly><input type="checkbox"><div class="track"><div class="handle"></div></div></div>',
scope: {
ngModel: '=',
ngValue: '=',
ngChecked: '=',
ngChange: '&'
},
transclude: true,
template: '<div class="item item-toggle">' +
'<div ng-transclude></div>' +
'<label class="toggle">' +
'<input type="checkbox" ng-model="ngModel" ng-value="ngValue" ng-change="ngChange()">' +
'<div class="track">' +
'<div class="handle"></div>' +
'</div>' +
'</label>' +
'</div>',
link: function($scope, $element, $attr, ngModel) {
var checkbox, handle;
compile: function(element, attr) {
var input = element.find('input');
if(attr.name) input.attr('name', attr.name);
if(attr.ngChecked) input.attr('ng-checked', 'ngChecked');
if(attr.ngTrueValue) input.attr('ng-true-value', attr.ngTrueValue);
if(attr.ngFalseValue) input.attr('ng-false-value', attr.ngFalseValue);
if(!ngModel) { return; }
// return function link($scope, $element, $attr, ngModel) {
// var el, checkbox, track, handle;
checkbox = $element.children().eq(0);
handle = $element.children().eq(1);
// el = $element[0].getElementsByTagName('label')[0];
// checkbox = el.children[0];
// track = el.children[1];
// handle = track.children[0];
if(!checkbox.length || !handle.length) { return; }
// $scope.toggle = new ionic.views.Toggle({
// el: el,
// track: track,
// checkbox: checkbox,
// handle: handle
// });
$scope.toggle = new ionic.views.Toggle({
el: $element[0],
checkbox: checkbox[0],
handle: handle[0]
});
// ionic.on('drag', function(e) {
// console.log('drag');
// $scope.toggle.drag(e);
// }, handle);
$scope.toggleIt = function(e) {
$scope.toggle.tap(e);
ngModel.$setViewValue(checkbox[0].checked);
};
ngModel.$render = function() {
$scope.toggle.val(ngModel.$viewValue);
};
// }
}
};
});

View File

@@ -0,0 +1,30 @@
describe('Ionic Checkbox', function() {
var el, scope, compile;
beforeEach(module('ionic.ui.checkbox'));
beforeEach(inject(function($compile, $rootScope) {
compile = $compile;
scope = $rootScope;
}));
it('should set the checkbox name', function() {
el = compile('<checkbox name="myname"></checkbox>')(scope);
var input = el.find('input');
expect(input.attr('name')).toEqual('myname');
});
it('should setup checkbox markup', function() {
el = compile('<checkbox>INNER TEXT</checkbox>')(scope);
expect(el.hasClass('item')).toEqual(true);
expect(el.hasClass('item-checkbox')).toEqual(true);
var label = el.find('label');
expect(label.hasClass('checkbox')).toEqual(true);
var input = el.find('input');
expect(input.attr('type')).toEqual('checkbox');
var div = el.find('div');
expect(div.hasClass('item-content')).toEqual(true);
expect(div.text()).toEqual('INNER TEXT');
});
});

View File

@@ -9,14 +9,14 @@ describe('Ionic Toggle', function() {
el = $compile('<toggle ng-model="data.name"></toggle>')($rootScope);
}));
it('Should load', function() {
xit('Should load', function() {
var toggleView = el.isolateScope().toggle;
expect(toggleView).not.toEqual(null);
expect(toggleView.checkbox).not.toEqual(null);
expect(toggleView.handle).not.toEqual(null);
});
it('Should toggle', function() {
xit('Should toggle', function() {
var toggle = el.isolateScope().toggle;
expect(toggle.val()).toBe(false);
el.click();
@@ -25,7 +25,7 @@ describe('Ionic Toggle', function() {
expect(toggle.val()).toBe(false);
});
it('Should disable and enable', function() {
xit('Should disable and enable', function() {
rootScope.data = { isDisabled: false };
el = compile('<toggle ng-model="data.name" ng-disabled="data.isDisabled"></toggle>')(rootScope);
@@ -45,4 +45,5 @@ describe('Ionic Toggle', function() {
el.click();
expect(toggle.el.getAttribute('disabled')).not.toBe('disabled');
});
});

View File

@@ -0,0 +1,139 @@
<!DOCTYPE html>
<html ng-app="ionicApp">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Tap Inputs</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<link rel="stylesheet" href="../../../../dist/css/ionic.css">
<script src="../../../../dist/js/ionic.js"></script>
<script src="../../../../dist/js/angular/angular.js"></script>
<script src="../../../../dist/js/angular/angular-animate.js"></script>
<script src="../../../../dist/js/angular/angular-route.js"></script>
<script src="../../../../dist/js/angular/angular-touch.js"></script>
<script src="../../../../dist/js/angular/angular-sanitize.js"></script>
<script src="../../../../dist/js/angular-ui/angular-ui-router.js"></script>
<script src="../../../../dist/js/ionic-angular.js"></script>
</head>
<body>
<div ng-controller="MyCtrl">
<header-bar title="'Tap Inputs'" type="bar-positive"></header-bar>
<content has-header="true">
<form name="myForm">
<div class="list">
<div class="item item-divider">
Checkbox
</div>
<checkbox ng-model="value1">
Checkbox Value 1
</checkbox>
<div class="item">
Value 1:
<input type="checkbox" ng-model="value1">
{{value1}}
</div>
<checkbox ng-model="value2" ng-true-value="YES" ng-false-value="NO">
Checkbox Value 2
</checkbox>
<div class="item">
Value 2:
<input type="checkbox" ng-model="value2" ng-true-value="YES" ng-false-value="NO">
{{value2}}
</div>
<checkbox ng-model="value3" ng-checked="true" ng-true-value="yup" ng-false-value="nope">
Checkbox Initially checked with ng-checked=true, value: {{ value3 }}
</checkbox>
<checkbox ng-model="value4" ng-change="checkboxChange()" ng-true-value="yup" ng-false-value="nope">
Checkbox Change: {{ value4ChangeValue }}
</checkbox>
<div class="item item-divider">
Toggle
</div>
<toggle ng-model="toggle1">
Toggle 1: {{ toggle1 }}
</toggle>
<toggle ng-model="toggle2" ng-true-value="yup" ng-false-value="nope">
Toggle 2: {{ toggle2 }}
</toggle>
<toggle ng-model="toggle3" ng-checked="true">
Toggle 3, ng-checked initially set to true, {{ toggle3 }}
</toggle>
<toggle ng-model="toggle4" ng-change="toggleChange()" ng-true-value="yup" ng-false-value="nope">
Toggle Change: {{ toggle4ChangeValue }}
</toggle>
<div class="item">
Toggle 1:
<input type="checkbox" ng-model="toggle1">,
Toggle 2:
<input type="checkbox" ng-model="toggle2" ng-true-value="yup" ng-false-value="nope">,
</div>
<div class="item item-divider">
Radio
</div>
<radio
ng-repeat="radioItem in radioItems"
ng-value="radioItem.value"
ng-model="selectedValues.radio"
ng-change="radioChanged()">
{{ radioItem.text }}
</radio>
<div class="item">
Selected Radio Value: {{ selectedValues.radio }},
Changed: {{ radioChangeCount }},
Watch Count: {{ radioWatchCount }}
</div>
</div>
</form>
</content>
</div>
<script>
angular.module('ionicApp', ['ionic'])
.controller('MyCtrl', function($scope) {
$scope.value1 = true;
$scope.value2 = 'NO';
$scope.checkboxChange = function() {
$scope.value4ChangeValue = 'Random number: ' + Math.floor(Math.random() * 1000);
};
$scope.toggleChange = function() {
$scope.toggle4ChangeValue = 'Random number: ' + Math.floor(Math.random() * 1000);
};
$scope.radioItems = [
{ text: 'Green Back Packers', value: 'packers' },
{ text: 'Minnesota Vikings', value: 'vikings' },
{ text: 'Chicago Bears', value: 'bears' },
];
$scope.selectedValues = { radio: 'packers' };
$scope.radioChangeCount = 0;
$scope.radioChanged = function() {
$scope.radioChangeCount++;
};
$scope.radioWatchCount = 0;
$scope.$watch('selectedValues.radio', function(val) {
$scope.radioWatchCount++;
})
});
</script>
</body>
</html>

View File

@@ -37,7 +37,7 @@
});
} else if(ele.type === "checkbox") {
ele.checked = !ele.checked;
ionic.trigger('change', {
ionic.trigger('click', {
target: ele
});
} else if(ele.type === "submit" || ele.type === "button") {

View File

@@ -5,6 +5,7 @@
initialize: function(opts) {
this.el = opts.el;
this.checkbox = opts.checkbox;
this.track = opts.track;
this.handle = opts.handle;
this.openPercent = -1;
},
@@ -16,8 +17,8 @@
},
drag: function(e) {
var slidePageLeft = this.checkbox.offsetLeft + (this.handle.offsetWidth / 2);
var slidePageRight = this.checkbox.offsetLeft + this.checkbox.offsetWidth - (this.handle.offsetWidth / 2);
var slidePageLeft = this.track.offsetLeft + (this.handle.offsetWidth / 2);
var slidePageRight = this.track.offsetLeft + this.track.offsetWidth - (this.handle.offsetWidth / 2);
if(e.pageX >= slidePageRight - 4) {
this.val(true);
@@ -38,7 +39,7 @@
} else if(openPercent === 100) {
this.val(true);
} else {
var openPixel = Math.round( (openPercent / 100) * this.checkbox.offsetWidth - (this.handle.offsetWidth) );
var openPixel = Math.round( (openPercent / 100) * this.track.offsetWidth - (this.handle.offsetWidth) );
openPixel = (openPixel < 1 ? 0 : openPixel);
this.handle.style.webkitTransform = 'translate3d(' + openPixel + 'px,0,0)';
}