On Github rhettl / ngModelController-slides
this is me. I am not in many places yet and I haven't been on the scene long, but I have been working hard and learning much.
Don't view your directive as a fine place to put repetitive HTML, instead view it as a way to teach HTML new tricks
angular.module('testApp', []).directive('pagination', [function () {
return {
restrict: 'A',
scope: {
span: '=',
current: '=',
total: '=',
nextPrev: '=?',
firstLast: '=?',
changePage: '&'
},
templateURL: "/partials/paginate.html",
link: function(scope, element, attrs) {
//Creation and DOM Manipulation data goes here.
}
};
}]);
I'd like to point out:
<range-slider min="0" max="100" ng-model-low="low" ng-model-high="high"></range-slider>
angular.module('jQueryUI', []).directive('rangeSlider', [function() {
var noop = angular.noop;
return {
restrict: "EA",
replace: true,
template: '<div class="slider"></div>',
scope: {
step: '@?',
min: '@',
max: '@',
ngModelLow: '=',
ngModelHigh: '=',
stop: '&?',
slide: '&?'
},
link: function(scope, elem, attrs) {
var slider,
externalChange = function(){
slider.slider('values', [scope.ngModelLow, scope.ngModelHigh]);
},
setValues = function(values){
values = checkLowHigh(values);
scope.$apply(function(){
scope.ngModelLow = values[0];
scope.ngModelHigh = values[1];
});
},
checkLowHigh = function(vals){
if (typeof vals === 'undefined' || vals.length !== 2)
vals = [min, max];
var low = vals[0], high = vals[1];
if (high < low){
var temp = high;
high = low; low = temp;
bounceBack = true;
}
if (low < min) {
low = min;
bounceBack = true;
}
if (high > max) {
high = max;
bounceBack = true;
}
return [low, high];
};
scope.stop = scope.stop || noop;
scope.slide = scope.slide || noop;
scope.min = parseFloat(scope.min);
scope.max = parseFloat(scope.max);
scope.step = typeof scope.step !== 'undefined' ? scope.step : 1;
scope.ngModelLow = typeof scope.ngModelLow !== 'undefined' ? scope.ngModelLow : scope.min;
scope.ngModelHigh = typeof scope.ngModelHigh !== 'undefined' ? scope.ngModelHigh : scope.max;
slider = elem.slider({
animate: true,
range: true,
step: scope.step,
min: scope.min,
max: scope.max,
values: [scope.ngModelLow, scope.ngModelHigh],
slide: function(e, ui){
setValues(ui.values);
scope.slide({
values: ui.values,
low: ui.values[0],
high: ui.values[1]
});
},
stop: function(e, ui){
scope.stop({
values: ui.values,
low: ui.values[0],
high: ui.values[1]
});
}
});
scope.$watch('ngModelLow', externalChange);
scope.$watch('ngModelHigh', externalChange);
}
};
}]);
This is my first pass at a jQuery UI range slider.
A Few Problems:
angular.module('jQueryUI', []).directive('rangeSlider', [function() {
var noop = angular.noop;
return {
restrict: "EA",
scope: {
step: '@?',
min: '@',
max: '@',
ngModelLow: '=',
ngModelHigh: '=',
stop: '&?',
slide: '&?'
},
link: function(scope, elem, attrs) {
/* Linking code Here */
}
};
}]);
slide: function(e, ui){
setValues(ui.values);
scope.slide({
values: ui.values,
low: ui.values[0],
high: ui.values[1]
});
}
/* ... */
setValues = function(values){
console.log('internal', values);
values = checkLowHigh(values);
scope.$apply(function(){
scope.ngModelLow = values[0];
scope.ngModelHigh = values[1];
});
}
externalChange = function(){
console.log('external', [scope.ngModelLow, scope.ngModelHigh]);
slider.slider('values', [scope.ngModelLow, scope.ngModelHigh]);
}
scope.$watch('ngModelLow', externalChange);
scope.$watch('ngModelHigh', externalChange);
Ok, here is where we run into problems
Top
Bottom
This creates 2 way binding.
angular.module('jQueryUI', []).directive('rangeSlider', [function() {
var noop = angular.noop;
return {
restrict: "EA",
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
if (!ngModel
|| typeof attrs.min === 'undefined'
|| typeof attrs.max === 'undefined'){
return;
}
var slider, bounceBack = false,
step = scope.$eval(attrs.step) || 1,
min = scope.$eval(attrs.min),
max = scope.$eval(attrs.max),
checkLowHigh = function(vals){
if (typeof vals === 'undefined' || vals.length !== 2)
vals = [min, max];
var low = vals[0], high = vals[1];
if (high < low){
var temp = high;
high = low; low = temp;
bounceBack = true;
}
if (low < min) {
low = min;
bounceBack = true;
}
if (high > max) {
high = max;
bounceBack = true;
}
return [low, high];
};
//ngModel.$parsers.push(checkLowHigh);
ngModel.$formatters.push(checkLowHigh);
slider = elem.slider({
animate: true,
range: true,
step: step,
min: min,
max: max,
values: ngModel.$viewValue,
slide: function(e, ui){
scope.$apply(function(){
ngModel.$setViewValue(ui.values);
});
},
stop: function(e, ui){
scope.$apply(function(){
scope.$eval(attrs.ngStop, {
values: ui.values,
low: ui.values[0],
high: ui.values[1]
});
});
}
});
ngModel.$render = function(){
if (bounceBack) {
bounceBack = false;
ngModel.$setViewValue(ngModel.$viewValue);
}
slider.slider('values', ngModel.$viewValue);
};
}
};
}]);
angular.module('jQueryUI', []).directive('rangeSlider', [function() {
var noop = angular.noop;
return {
restrict: "EA",
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
if (!ngModel
|| typeof attrs.min === 'undefined'
|| typeof attrs.max === 'undefined'){
return;
}
/* ... */
}
}
}]);
slider = elem.slider({
/* ... */
values: ngModel.$viewValue,
slide: function(e, ui){
scope.$apply(function(){
ngModel.$setViewValue(ui.values);
});
}
/* ... */
});
ngModel.$render = function(){
/* ... */
slider.slider('values', ngModel.$viewValue);
};
Modify and/or control the data comming in and going out of the ngModel
var checkLowHigh = function(vals){
if (typeof vals === 'undefined' || vals.length !== 2)
vals = [min, max];
var low = vals[0], high = vals[1];
if (high < low){
var temp = high;
high = low; low = temp;
}
if (low < min) {
low = min;
}
if (high > max) {
high = max;
}
return [low, high];
};
//ngModel.$parsers.unshift(checkLowHigh);
ngModel.$formatters.push(checkLowHigh);
var ngListDirective = function() {
return {
require: 'ngModel',
link: function(scope, element, attr, ctrl) {
var match = /\/(.*)\//.exec(attr.ngList),
separator = match && new RegExp(match[1])
|| attr.ngList || ',';
var parse = function(viewValue) {
// If the viewValue is invalid (say required
// but empty) it will be `undefined`
if (isUndefined(viewValue)) return;
var list = [];
if (viewValue) {
forEach(viewValue.split(separator), function(value) {
if (value) list.push(trim(value));
});
}
return list;
};
ctrl.$parsers.push(parse);
ctrl.$formatters.push(function(value) {
if (isArray(value)) {
return value.join(', ');
}
return undefined;
});
// Override the standard $isEmpty because an empty
// array means the input is empty.
ctrl.$isEmpty = function(value) {
return !value || !value.length;
};
}
};
};
View in Github
From the angular source -- I recommend reading the source from time to time.
var ngChangeDirective = valueFn({
require: 'ngModel',
link: function(scope, element, attr, ctrl) {
ctrl.$viewChangeListeners.push(function() {
scope.$eval(attr.ngChange);
});
}
});
View in Github
Also from the angular source.
ngDollar
var ngDollarDirective = ['$timeout', function($timeout) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) {
var deci = '.',
comma = ',',
deciPlaces = 2,
curSign = '$',
keyTimeoutPromise,
addFormat = function(n) {
var sign = curSign,
c = isNaN(c = Math.abs(deciPlaces)) ? 2 : deciPlaces,
d = deci ? deci : ".",
t = comma ? comma : ",",
s = n < 0 ? "-" : "",
i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
j = (j = i.length) > 3 ? j % 3 : 0;
return s + sign + (j ? i.substr(0, j) + t : "")
+ i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t)
+ (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
},
removeFormat = function(n) {
return parseFloat(n.replace(/[^0-9\.]/gi, '')) || 0;
},
refreshElem = function() {
ngModel.$setViewValue(elem.val());
elem.val(addFormat(removeFormat(elem.val())));
};
ngModel.$parsers.push(removeFormat);
ngModel.$formatters.push(addFormat);
elem.bind('keyup blur', function(e) {
if (keyTimeoutPromise) {
$timeout.cancel(keyTimeoutPromise);
keyTimeoutPromise = null;
}
var commit = (e.type === 'blur'
|| (e.type === 'keyup' && e.keyCode === 13));
if (commit) {
refreshElem();
} else {
keyTimeoutPromise = $timeout(refreshElem, 1200);
}
});
//ngModel.$render = function(){
// elem.val(ngModel.$viewValue);
//};
}
};
}];
Code included in js/iShowUI.js
This was intended to be an input that would always be formatted as a currency but would hold a number in the model.