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.