Angular custom directive not setting value after promise resolve - javascript

I have a custom directive, it works great when user is entering value, the problem is when loading the form, the input field is not being rendered.
Here is my directive:
var cuitModule = angular.module('cuitModule', []).directive('cuitDirective', ['$filter', function ($filter) {
return {
require: '?ngModel',
link: link,
restrict: 'E',
scope: {
cuitPlaceholder: '=placeholder'
},
templateUrl: 'js/common/directives/cuit/cuit.directive.html'
};
/*
Intended use:
<cuit-directive placeholder='prompt' model='someModel.cuit'></cuit-directive>
Where:
someModel.cuit: {String} value which to bind only the numeric characters [0-9] entered
ie, if user enters 20-33452648-9, value of 20334526489 will be bound to model
prompt: {String} text to keep in placeholder when no numeric input entered
*/
function link(scope, element, attributes, ngModel) {
// scope.inputValue is the value of input element used in template
scope.inputValue = ngModel.$viewValue;
scope.$watch('inputValue', function (value, oldValue) {
value = String(value);
var number = value.replace(/[^0-9]+/g, '');
// scope.cuitModel = number;
scope.inputValue = $filter('cuit')(number);
var valid = validarCuit(number);
ngModel.$setValidity('required', valid);
if (valid) {
ngModel.$setViewValue(number);
}
});
//source https://es.wikipedia.org/wiki/Clave_%C3%9Anica_de_Identificaci%C3%B3n_Tributaria#C.C3.B3digo_Javascript
function validarCuit(cuit) {
if (cuit.length !== 11) {
return false;
}
var acumulado = 0;
var digitos = cuit.split('');
var digito = digitos.pop();
for (var i = 0; i < digitos.length; i++) {
acumulado += digitos[9 - i] * (2 + (i % 6));
}
var verif = 11 - (acumulado % 11);
if (verif == 11) {
verif = 0;
}
return digito == verif;
}
}}]).filter('cuit', function () {
/*
Format cuit as: xx-xxxxxxxx-x
or as close as possible if cuit length is not 10
*/
return function (number) {
/*
#param {Number | String} number - Number that will be formatted as cuit number
Returns formatted number: ##-########-#
if number.length < 2: ##
if number.length < 10: ##-########
if number.length === 11: ##-########-#
*/
if (!number) {
return '';
}
number = String(number);
// Will return formattedNumber.
// If phonenumber isn't longer than an area code, just show number
var formattedNumber = number;
//Type 20, 23, 24 y 27 Personas FĂ­sicas or 30, 33 y 34 Empresas
var type = number.substring(0, 2);
var main = number.substring(2, 10);
var verifyNumber = number.substring(10, 11);
if (main) {
formattedNumber = (type + '-' + main);
}
if (verifyNumber) {
formattedNumber += ('-' + verifyNumber);
}
return formattedNumber;
};});
This is the html:
<cuit-directive placeholder="'CUIT'" ng-model='vm.merchant.idNumber' required></cuit-directive>
I am invoking it within a form of course.
I am getting the data to my controller through a rest service, so I am doing something like:
function EditMerchantCtrl($state, $ionicHistory, merchantsService, $ionicPopup, $timeout, $ionicLoading) {
var vm = this;
function init(){
merchantsService.get().then(
function(response){
vm.merchant = response.data;
});
}}
I don't know why I can't get that field populated after receiving the response from the service. Any help would be much appreciated.

You should implement the $render function of the ngModelController, try something like this:
ngModel.$render = function() {
scope.inputValue = ngModel.$viewValue;
}
Hope it helps.

Related

add decimal point and thousand separator in to textbox

I am tying to add thousand separator and decimal point to my text box.
I am using below directive also
.directive('format', function ($filter) {
'use strict';
return {
require: '?ngModel',
link: function (scope, elem, attrs, ctrl) {
if (!ctrl) {
return;
}
ctrl.$formatters.unshift(function () {
return $filter('number')(ctrl.$modelValue);
});
ctrl.$parsers.unshift(function (viewValue) {
var plainNumber = viewValue.replace(/[\,\.]/g, ''),
b = $filter('number')(plainNumber);
elem.val(b);
return plainNumber;
});
}
};
})
this is my Demo
i need to modify this.
When user enter 500,000, it should be like 500,000.00
and user can be enter 5000.50 also.
How i modify this, can u help
Take the decimal placement out of the users control.
num = 599993863737
num = str(num).replace('.','')
num = float(num[:len(num)-2]+'.'+num[-2:])
print(num)
5999938637.37
You can use toFixed() and regex
function currency(el){
a = parseFloat(el.value);
a = a.toFixed(2);
a=a.toString();
var b = a.replace(/[^\d\.]/g,'');
var dump = b.split('.');
var c = '';
var lengthchar = dump[0].length;
var j = 0;
for (var i = lengthchar; i > 0; i--) {
j = j + 1;
if (((j % 3) == 1) && (j != 1)) {
c = dump[0].substr(i-1,1) + ',' + c;
} else {
c = dump[0].substr(i-1,1) + c;
}
}
if(dump.length>1){
if(dump[1].length>0){
c += '.'+dump[1];
}else{
c += '.';
}
}
console.log(c);
}
<input type='text' onkeyup='currency(this)'>

How to capitalize first and third letter?

I want to capitalize first letter and third letter in my textarea.
I can capitalize only first letter and then every next letters and words are transformed to lowercase.
If there is any solution for this problem, please tell me.
I am using AngularJS.
This is what im trying and did.
link: function (scope, iElement, iAttrs, controller) {
//console.log('init');
controller.$parsers.push(function (inputValue) {
var transformedInput = (!!inputValue) ? inputValue.charAt(0).toUpperCase() + inputValue.substr(1).toLowerCase() : '';
if (transformedInput != inputValue) {
controller.$setViewValue(transformedInput);
controller.$render();
}
return transformedInput;
});
This works only for first letter, it transforms to uppercase and then transforms another letter and words to lowercase.
I tried to change my code into this but nothing.
var transformedInput = (!!inputValue) ? inputValue.charAt(0).toUpperCase() + inputValue.substr(1).toLowerCase() + inputValue.charAt(3).toUpperCase() + inputValue.substr(4).toLowerCase(): '';
Have a look at this. Same as what you are doing just using for loop to identify the character index to modify.
var inputValue = "test";
var transformedInput = '';
if(inputValue){
for(var i=0; i<inputValue.length; i++){
if(i===0 || i=== 2){
transformedInput += inputValue.charAt(i).toUpperCase();
} else {
transformedInput += inputValue.charAt(i).toLowerCase();
}
}
}
console.log(transformedInput);
Here is a function to capitalize chars at specific positions
function capitalizeAtPositions(string, indexes) {
(indexes || []).forEach(function(index) {
if (string.length < index) return;
string = string.slice(0, index) +
string.charAt(index).toUpperCase() + string.slice(index+1);
});
return string;
}
Run it as follows:
var test = "abcdefg";
var result = capitalizeAtPositions(test, [0, 2]);
//AbCdefg
In your case i think it will be something like (can't test it without jsfiddle):
var transformedInput = capitalizeAtPositions(inputValue || '', [0, 2]);
My simple solution
var inputValue = 'your value';
function toUpper (str) {
var result = '';
for (var i = 0; i < str.length; i++) {
if (i === 0 || i === 2) {
result += str[i].toUpperCase();
} else {
result += str[i].toLowerCase();
}
}
return result;
}
var transformedInput = toUpper(inputValue);
Seeing how you need to have the input change as you type, you'll probably need a directive; here's a one to capitalize the given letters of any input with an ng-model:
https://plnkr.co/edit/hWhmjQWdrghvsL20l3DE?p=preview
app.directive('myUppercase', function() {
return {
scope: {
positions: '=myUppercase'
},
require: 'ngModel',
link: function(scope, elem, attrs, ngModelCtrl) {
scope.positions = scope.positions || []
function makeString(string) {
if (!string) return;
angular.forEach(scope.positions, function(pos) {
string = string.slice(0, pos) + string.slice(pos, pos+1).toUpperCase() + string.slice(pos + 1)
console.log(string)
})
return string;
}
ngModelCtrl.$parsers.push(makeString)
ngModelCtrl.$formatters.push(makeString)
}
}
})
HTML:
<input ng-model="value" my-uppercase="[0, 2]">
My solution for "McArturo" this type of text you want
$("#LastName").keyup(function () {
var last_name = $("#LastName").val();
var op = last_name.substr(0, 2);
if (op == "mc" || op == "Mc" || op == "MC") {
$("#LastName").val("Mc" + (last_name.charAt(2).toUpperCase()) + last_name.substr(3).toLowerCase());
} else {
$("#LastName").val(last_name.charAt(0).toUpperCase() + last_name.substr(1).toLowerCase());
}});

Turning JSON object value into decimal number after calculation

I have pulled in some data for my app via an external JSON url which has resulted in the value I require, which is currently a string that is "0.00"
result.data.app_payamount = "0.00"
When I convert my strings into numbers and calculate a value I am only being returned a part number and not a full decimal value used for currency.
How can I edit this code so the payamount displays a full decimal number suitable for currency?
var deferred = $q.defer();
var results = response.data;
var urlStart = 'http://exmaple.com/api';
if (response.config.url.startsWith(urlStart)) {
angular.forEach(results, function(result, key) {
result.data.CardFee = 2.00;
result.data.app_bookingfee = result.data.CardFee;
result.data.app_payamount = +result.data.app_subtotal + +result.data.app_handling + -result.data.app_discount + +result.data.app_adjustment + +result.data.app_bookingfee;
});
In js, you can specify the number of digits like this:
n = n.toFixed(2);
Try to use Number.toFixed() here.
var deferred = $q.defer();
var results = response.data;
var urlStart = 'http://exmaple.com/api';
if (response.config.url.startsWith(urlStart)) {
angular.forEach(results, function(result, key) {
result.data.CardFee = 2.00;
result.data.app_bookingfee = result.data.CardFee;
result.data.app_payamount = +result.data.app_subtotal + +result.data.app_handling + -result.data.app_discount + +result.data.app_adjustment + +result.data.app_bookingfee;
result.data.app_payamount = result.data.app_payamount.toFixed(2);
});
Use number.toFixed(2):
var n = 2;
var nStringInteger = n.toFixed(0); // "2"
var nString1Decimal = n.toFixed(1); // "2.0"
var nString2Decimal = n.toFixed(2); // "2.00"
Use parseFloat and toFixed
<!DOCTYPE html>
<html>
<body>
<p>Click the button to parse different strings.</p>
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
<p id="demo2"></p>
<script>
function myFunction() {
var a = parseFloat("10.3265");
var b = parseFloat("10.00");
var c = parseFloat("10.33");
var n = a + b + c;
document.getElementById("demo").innerHTML = n;
document.getElementById("demo2").innerHTML = n.toFixed(2);
}
</script>
</body>
</html>
Use following currency directive to apply decimal places.
app.directive('currency', function ($filter, $locale) {
return {
require: 'ngModel',
scope: {
min: '=min',
max: '=max',
ngRequired: '=ngRequired'
},
link: function (scope, element, attrs, ngModel) {
function clearValue(value) {
value = String(value);
var dSeparator = $locale.NUMBER_FORMATS.DECIMAL_SEP;
var clear = value.match(/[\+\-0-9\.]/g);
clear = clear ? clear.join("") : 0;
return clear;
}
ngModel.$parsers.push(function (viewValue) {
cVal = clearValue(viewValue);
return parseFloat(cVal);
});
element.on("blur", function () {
if (isNaN(ngModel.$modelValue)) {
ngModel.$modelValue = 0;
element.val($filter('currency')(clearValue(ngModel.$modelValue)));
}
else {
element.val($filter('currency')(ngModel.$modelValue));
}
});
ngModel.$formatters.unshift(function (value) {
return $filter('currency')(value);
});
scope.$watch(function () {
return ngModel.$modelValue
}, function (newValue, oldValue) {
runValidations(newValue)
})
function runValidations(cVal) {
if (!scope.ngRequired && isNaN(cVal)) {
return
}
if (scope.min) {
var min = parseFloat(scope.min)
ngModel.$setValidity('min', cVal >= min)
}
if (scope.max) {
var max = parseFloat(scope.max)
ngModel.$setValidity('max', cVal <= max)
}
}
}
}
});

How to define multiple similar directives?

I need a couple of directives performing input field cleanup and validation, just like in this question. All of them are the same except for the cleanup and validation functions themselves and the field name. Currently, I'm copying it like
angular.module('myModule')
.directive('validateFoo', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, element, attrs, ngModel) {
// THESE THREE LINES SHOULD BE ARGUMENTS
var isValid = isValidFoo;
var clean = cleanFoo;
var name = "foo";
element = $(element);
var cleanAndValidate = function(x) {
var y = clean(x);
var ok = isValid(y);
ngModel.$setValidity(name, ok);
return y;
};
ngModel.$parsers.push(cleanAndValidate);
var fix = function() {
var x = element.val();
var y = clean(x);
if (x===y) return y;
var e = element[0];
var start = e.selectionStart;
var end = e.selectionEnd;
element.val(y);
var delta = y.length - x.length;
e.setSelectionRange(start + delta, end + delta);
return y;
};
element.keyup(function() {
fix();
});
}
};
})
which is obviously a bad idea. I guess I should be able to do it using a closure, but I'd also like to preserve the overall structure (all my files start with angular.module followed by a definition). If I had access to the directive name in the body, I could get the three variables from their defining object.
All of them are the same except for the cleanup and validation
functions themselves and the field name
I think you need to add a scope to your custom directive; then you can pass in the functions and field that need to be processed. Something like this:
.directive('validateFoo', function() {
return {
restrict: 'A',
require: 'ngModel',
scope : {
// DEFINE These Arguments in the scope
isvalid : "=isvalid",
clean : "=clean",
name : "=name"
}
link: function($scope, element, attrs, ngModel) {
element = $(element);
// modify this method to access your clean/isvalid/name values in the $scope
var cleanAndValidate = function(x) {
var y = $scope.clean(x);
var ok = $scope.isValid(y);
ngModel.$setValidity($scope.name, ok);
LOG name, x, y, ok
return y;
};
ngModel.$parsers.push(cleanAndValidate);
var fix = function() {
var x = element.val();
var y = clean(x);
if (x===y) return y;
var e = element[0];
var start = e.selectionStart;
var end = e.selectionEnd;
element.val(y);
var delta = y.length - x.length;
e.setSelectionRange(start + delta, end + delta);
return y;
};
element.keyup(function() {
fix();
});
}
};
})
When you use the directive, you can pass in the function and values, sort of like this:
<validate-foo isvalid="isValidFoo" clean="cleanfoo" name="foo" />

Knockout: Combining 2 custom bindings for digits - Financial data

good Day
I found the following two fiddles that does exactly what I want:
The first Fiddle gives me decimal notation.
The second Fiddle gives me digital grouping of numbers.
My Question: How do I combine both of them into one such that I can just use it like this:
<b data-bind="commaDecimalFormatter: myNumber">This will output both demical notation and digital grouping</b>
====================================================================================================================================================================
Fiddle 1 code:
// Formatting Functions
function formatWithComma(x, precision, seperator) {
var options = {
precision: precision || 2,
seperator: seperator || '.'
}
var formatted = parseFloat(x,10).toFixed( options.precision );
var regex = new RegExp(
'^(\\d+)[^\\d](\\d{' + options.precision + '})$');
formatted = formatted.replace(
regex, '$1' + options.seperator + '$2');
return formatted;
}
function reverseFormat(x, precision, seperator) {
var options = {
precision: precision || 2,
seperator: seperator || ','
}
var regex = new RegExp(
'^(\\d+)[^\\d](\\d+)$');
var formatted = x.replace(regex, '$1.$2');
return parseFloat( formatted );
}
// END: Formatting Functions
// Custom Binding - place this in a seperate .js file and reference it in your html
ko.bindingHandlers.commaDecimalFormatter = {
init: function(element, valueAccessor) {
var observable = valueAccessor();
var interceptor = ko.computed({
read: function() {
return formatWithComma( observable() );
},
write: function(newValue) {
observable( reverseFormat(newValue) );
}
});
if( element.tagName == 'INPUT' )
ko.applyBindingsToNode( element , {
value: interceptor
} );
else
ko.applyBindingsToNode( element , {
text: interceptor
} );
}
}
// this is your viewmodel
var vm = {
myNumber: ko.observable(100000)
}
// when the DOM is ready, call ko.applyBindings with your viewmodel
$(function() {
ko.applyBindings(vm);
});
FIDDLE 2 Code:
(function(){
var format = function(value) {
toks = value.toFixed(2).replace('-', '').split('.');
var display = '$' + $.map(toks[0].split('').reverse(), function(elm, i) {
return [(i % 3 === 0 && i > 0 ? ',' : ''), elm];
}).reverse().join('') + '.' + toks[1];
return value < 0 ? '-' + display : display;
};
ko.subscribable.fn.money = function() {
var target = this;
var writeTarget = function(value) {
var stripped=value
.replace(/[^0-9.-]/g, '');
target(parseFloat(stripped));
};
var result = ko.computed({
read: function() {
return target();
},
write: writeTarget
});
result.formatted = ko.computed({
read: function() {
return format(target());
},
write: writeTarget
});
result.isNegative = ko.computed(function(){
return target()<0;
});
return result;
};
})();
//Wire it up
$(function() {
var viewModel = {
Cash: ko.observable(1000000).money(),
};
viewModel.Total = ko.computed(function() {
return this.Cash();
}, viewModel).money();
ko.applyBindings(viewModel);
});
I cannot combine the two functions. Try the following, since it does what you want: Both Decimal notation and Digit grouping:
JS:
function formatPrice(price) {
return price.reverse().replace(/((?:\d{2})\d)/g, '$1 ').reverse();
}
// Need to extend String prototype for convinience
String.prototype.reverse = function() {
return this.split('').reverse().join('');
}
$('.myNumber').each(function(){
$(this).html(formatPrice($(this).html()));
});
See Fiddle
NOTE: You need to refresh the browser everytime for the jquery to format the output value(Read Only) into digit grouping...That is of course when you enter a new value into the editor screen(first field) and you don't see the digit grouping updated
I'd like to provide an alternative solution. You could also create a custom binding handler that does what you want (which would use the syntax you originally proposed).
ko.bindingHandlers. commaDecimalFormatter = {
update: function(element, valueAccessor, allValuesAccessor) {
// This gets the current value of the observable from your model
var value = ko.utils.unwrapObservable(valueAccessor());
// Manipulate `value` as desired using the bodies of the functions you mentioned
// Note: You don't want to use a global function, so actually take the bodies
// and put it here. Plain old JS :)
...
// Set the value on the element
jQuery(element).text(value);
}
};

Categories

Resources