Reputation: 93
This function should capitalize first letter for each word in input. But angular is throwing me "RangeError: Maximum call stack size exceeded". And only becouse of that ' ' space on line 9.
myApp.directive('capitalizeFirst', function(uppercaseFilter, $parse) {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var capitalize = function(inputValue) {
var capitalized = inputValue.split(' ').reduce(function(prevValue, word){
return prevValue + word.substring(0, 1).toUpperCase() + word.substring(1)+' ';
}, '');
if(capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
}
return capitalized;
}
var model = $parse(attrs.ngModel);
modelCtrl.$parsers.push(capitalize);
capitalize(model(scope));
}
};
});
here is the fiddle
http://jsfiddle.net/YyYnM/205/
Can someone explain this to me? I'm trying to figure this out for an hour now.
Upvotes: 2
Views: 2039
Reputation: 7299
The problem is here
var capitalize = function(inputValue) {
var capitalized = inputValue.split(' ').reduce(function(prevValue, word){
return prevValue + word.substring(0, 1).toUpperCase() + word.substring(1)+' ';
}, '');
It adds you an extra space every time you run the function.
Angular works the way that it runs cycles.
Eeverytime a change of one of the variables is detected it runs another cycle.
Here because of the extra space, the string is changed in an infinite loop and therefore angular dies.
An ugly solution is to add afterwards
capitalized = capitalized.substring(0, capitalized.length - 1);
Upvotes: 2
Reputation: 1176
The problem is not the ''
on line 9 as you suggested, but your use of the modelCtrl
. When you use modelCtrl.$setViewValue
modelCtrl
will run all the $parsers
again. Therefore it will invoke your capitalize
function recursivly until it rans out of stack.
All you need to do, to capitalize the input, is to push a function that changes the string to the $parsers
array. This will do the job:
myApp.directive('capitalizeFirst', function(uppercaseFilter, $parse) {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var capitalize = function(inputValue) {
var capitalized = inputValue.split(' ').reduce(function(prevValue, word){
return prevValue + word.substring(0, 1).toUpperCase() + word.substring(1)+' ';
}, '');
return capitalized;
}
modelCtrl.$parsers.push(capitalize);
}
};
});
function MyCtrl($scope) {
$scope.name = '';
}
Upvotes: 1
Reputation: 2241
I don't know what's wrong with your code but try this. DEMO
myApp.directive('capitalizeFirst', function (uppercaseFilter, $parse) {
return {
require: 'ngModel',
scope: {
ngModel: "="
},
link: function (scope, element, attrs, modelCtrl) {
scope.$watch("ngModel", function () {
scope.ngModel = scope.ngModel.replace(/^(.)|\s(.)/g, function(v){ return v.toUpperCase( ); });
});
}
};
});
Upvotes: 2