<html ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
<meta charset="UTF-8">
<title>Refactoring to AngularJS Directive - Demo</title>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<!-- <script src="https://raw.github.com/greengerong/ngmodel-format/master/src/ngmodel.format.js" type="text/javascript"></script> -->
</head>
<body ng-controller="ctr">
<div>
<form name="form">
<filedset>
<legend>
currency: default config
</legend>
<input type="text" ng-model="test" model-format="currency"/>
<hr/>
<pre>{{test | json}}</pre>
</filedset>
<filedset>
<legend>
currency: customer config for formatter
</legend>
<input type="text" ng-model="test1" model-format="currency"
formatter="formatter($modelValue,$filter,'$0.00');"/>
<hr/>
<pre>{{test1 | json}}</pre>
</filedset>
<filedset>
<legend>
currency: customer config for key down
</legend>
<input type="text" ng-model="test2" model-format="currency" name="test2"
key-down="all($event,$modelValue,$viewValue)"/>
<hr/>
<pre>{{test2 | json}}</pre>
</filedset>
<filedset>
<legend>
digit
</legend>
<input type="text" ng-model="test3" model-format="digit"
/>
<hr/>
<pre>{{test3 | json}}</pre>
</filedset>
<filedset>
<legend>
int
</legend>
<input type="text" ng-model="test4" model-format="int"
/>
<hr/>
<pre>{{test4 | json}}</pre>
</filedset>
<filedset>
<legend>
float
</legend>
<input type="text" ng-model="test5" model-format="float"
/>
<hr/>
<pre>{{test5 | json}}</pre>
</filedset>
<filedset>
<legend>
Radio box value to a boolean
</legend>
<div><input type="radio" ng-model="testBoolean" model-format="boolean" value="true"/>
<input type="radio" ng-model="testBoolean" model-format="boolean" value="false"/></div>
<hr/>
<pre>{{testBoolean | json}}</pre>
</filedset>
<filedset>
<legend>
Check box value to a Array
</legend>
<div><input ng-model="testToArray" type="checkbox" check-box-to-array="1"/>
<input ng-model="testToArray" type="checkbox" check-box-to-array="2"/></div>
<hr/>
<pre>{{testToArray | json}}</pre>
</filedset>
</form>
</div>
</body>
</html>
;
(function () {
angular.module('ngmodel.format', [])
.constant("modelFormatConfig", {
"currency": {
"formatter": function (args) {
var modelValue = args.$modelValue, filter = args.$filter;
return filter("currency")(modelValue);
},
"parser": function (args) {
var viewValue = args.$viewValue;
var num = viewValue.replace(/[^0-9.]/g, '');
var result = parseFloat(num, 10);
return isNaN(result) ? undefined : parseFloat(result.toFixed(2));
},
"isEmpty": function (value) {
return !value.$modelValue;
},
"keyDown": function (args) {
var event = args.$event, viewValue = args.$viewValue, modelValue = args.$modelValue;
if (!(smallKeyBoard(event) || numberKeyBpoard(event) || functionKeyBoard(event) || currencyKeyBoard(event, viewValue) || floatKeyBoard(event, viewValue) )) {
event.stopPropagation();
event.preventDefault();
}
}
},
"digit": {
"formatter": function (args) {
return args.$modelValue;
},
"parser": function (args) {
return args.$viewValue ? args.$viewValue.replace(/[^0-9]/g, '') : undefined;
},
"isEmpty": function (value) {
return !value.$modelValue;
},
"keyDown": function (args) {
var event = args.$event;
if (!(smallKeyBoard(event) || numberKeyBpoard(event) || functionKeyBoard(event))) {
event.stopPropagation();
event.preventDefault();
}
}
},
"int": {
"formatter": function (args) {
var modelValue = args.$modelValue, filter = args.$filter;
return filter("number")(modelValue);
},
"parser": function (args) {
var val = parseInt(args.$viewValue.replace(/[^0-9]/g, ''), 10);
return isNaN(val) ? undefined : val;
},
"isEmpty": function (value) {
return !value.$modelValue;
},
"keyDown": function (args) {
var event = args.$event;
if (!(smallKeyBoard(event) || numberKeyBpoard(event) || functionKeyBoard(event))) {
event.stopPropagation();
event.preventDefault();
}
}
},
"float": {
"formatter": function (args) {
var modelValue = args.$modelValue, filter = args.$filter;
return filter("number")(modelValue);
},
"parser": function (args) {
var val = parseFloat(args.$viewValue.replace(/[^0-9.]/g, '')),
ENOB = 3,
tempNum = Math.pow(10, ENOB);
return isNaN(val) ? undefined : Math.round(val * tempNum) / tempNum;
},
"isEmpty": function (value) {
return !value.$modelValue;
},
"keyDown": function (args) {
var event = args.$event, viewValue = args.$viewValue;
if (!(smallKeyBoard(event) || numberKeyBpoard(event) || functionKeyBoard(event) || floatKeyBoard(event, viewValue) )) {
event.stopPropagation();
event.preventDefault();
}
}
},
"boolean": {
"formatter": function (args) {
var modelValue = args.$modelValue;
if (!angular.isUndefined(modelValue)) {
return modelValue.toString();
}
},
"parser": function (args) {
var viewValue = args.$viewValue;
if (!angular.isUndefined(viewValue)) {
return viewValue.trim() === "true";
}
},
"isEmpty": function (value) {
return angular.isUndefined(value);
}
}
})
.directive("modelFormat", ["modelFormatConfig", "$filter", "$parse", function (modelFormatConfig, $filter, $parse) {
return {
require: 'ngModel',
link: function (scope, element, attrs, ctrl) {
var config = modelFormatConfig[attrs.modelFormat] || {};
var parseFuction = function (funKey) {
if (attrs[funKey]) {
var func = $parse(attrs[funKey]);
return (function (args) {
return func(scope, args);
});
}
return config[funKey];
};
var formatter = parseFuction("formatter");
var parser = parseFuction("parser");
var isEmpty = parseFuction("isEmpty");
var keyDown = parseFuction("keyDown");
var getModelValue = function () {
return $parse(attrs.ngModel)(scope);
};
if (keyDown) {
element.bind("blur",function () {
element.val(formatter({"$modelValue": getModelValue(), "$filter": $filter}));
}).bind("keydown", function (event) {
keyDown({"$event": event, "$viewValue": element.val(), "$modelValue": getModelValue()});
});
}
ctrl.$parsers.push(function (viewValue) {
return parser({"$viewValue": viewValue});
});
ctrl.$formatters.push(function (value) {
return formatter({"$modelValue": value, "$filter": $filter});
});
ctrl.$isEmpty = function (value) {
return isEmpty({"$modelValue": value});
};
}
};
}])
.directive("checkBoxToArray", [function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attrs, ctrl) {
var value = scope.$eval(attrs.checkBoxToArray);
ctrl.$parsers.push(function (viewValue) {
var modelValue = ctrl.$modelValue ? angular.copy(ctrl.$modelValue) : [];
if (viewValue === true && modelValue.indexOf(value) === -1) {
modelValue.push(value);
}
if (viewValue !== true && modelValue.indexOf(value) != -1) {
modelValue.splice(modelValue.indexOf(value), 1);
}
return modelValue.sort();
});
ctrl.$formatters.push(function (modelValue) {
return modelValue && modelValue.indexOf(value) != -1;
});
ctrl.$isEmpty = function ($modelValue) {
return !$modelValue || $modelValue.length === 0;
};
}
}
}]);
var smallKeyBoard = function (event) {
var which = event.which;
return (which >= 96 && which <= 105);
};
var numberKeyBpoard = function (event) {
var which = event.which;
return (which >= 48 && which <= 57) && !event.shiftKey;
};
var functionKeyBoard = function (event) {
var which = event.which;
return (which <= 40) || (navigator.platform.indexOf("Mac") > -1 && event.metaKey) || (navigator.platform.indexOf("Win") > -1 && event.ctrlKey);
};
var currencyKeyBoard = function (event, viewValue) {
var which = event.which;
return ( viewValue.toString().indexOf('$') === -1 && which === 52 && event.shiftKey);
};
var floatKeyBoard = function (event, viewValue) {
var which = event.which;
return [188].indexOf(which) != -1 || ( which === 190 || which === 110 ) && viewValue.toString().indexOf('.') === -1;
}
})();
angular.module("app", ["ngmodel.format"]).
controller("ctr", function ($scope) {
$scope.formatter = function (modelValue, filter, defaultValue) {
console.log("arguments", arguments);
if (modelValue) {
return filter("currency")(modelValue);
}
return defaultValue;
};
$scope.all = function () {
console.log("arguments", arguments);
return true;
};
});
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |