Reputation: 1055
I cannot force angular to fire $parsers.push when updating the input so, having this directive with the above test, how do you fire the $parsers.push ?
mainApp.directive('amountConverter', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModelController) {
var isInt = function(value) {
return !isNaN(parseInt(value, 10)) && (parseFloat(value, 10) == parseInt(value, 10));
},
convert = function(initial, multiplier, text) {
var amount = text.replace(initial, "");
if (!isInt(amount)) {
throw " Amount not a number";
}
return amount * multiplier;
};
//convert data from view format to model format
ngModelController.$parsers.push(function(value) {
if (value === null || value === undefined) {
return null;
}
var text = value.toUpperCase();
var amount = 0;
var initial = text.substring(text.length - 1);
if (initial === "B") {
amount = convert(initial, 1000000000, text);
} else if (initial === "M") {
amount = convert(initial, 1000000, text);
} else if (initial === "K") {
amount = convert(initial, 1000, text);
} else if (initial === "T") {
amount = convert(initial, 1000, text);
} else {
return value;
}
element[0].value = amount;
return amount; //converted
});
}
};
});
describe('Directives', function () {
var element, scope;
beforeEach(module('mainApp'));
beforeEach(inject(function ($compile, $rootScope) {
scope = $rootScope;
element = angular.element('<input type="text" data-ng-model="Amount" amount-Converter/>');
$compile(element)(scope);
scope.$digest();
}));
//////Jasmine Test
describe('amountConverter', function () {
it('should return change element state after click to be visible', function () {
element.scope().Amount = '10k';
element.scope().$apply();
expect(element[0].value).toBe('10000');
});
});
});
Upvotes: 4
Views: 3411
Reputation: 1694
= Directive
directive('numbersOnly', function(){
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModelController) {
ngModelController.$parsers.push(function (inputVal) {
if (inputVal == undefined) return ''
var onlyNumbers = inputVal.replace(/[^0-9]/g, '');
if (onlyNumbers != inputVal) {
ngModelController.$setViewValue(onlyNumbers);
ngModelController.$render();
}
return onlyNumbers;
});
}
};
})
= Spec
describe('Directive: numbersOnly', function () {
beforeEach(module('myApp'));
var rootScope,
scope,
element,
compile;
beforeEach(inject(function ($rootScope, $compile) {
scope = $rootScope.$new();
compile = $compile;
element = prepareElement("<input numbers-only ng-model='inputValue'></input>");
}));
// utility function
var prepareElement = function (elem) {
var el = compile(angular.element(elem))(scope);
body.append(el);
scope.$digest();
return el;
};
it('should accepts input value if its number', function(){
element.val('12345');
element.trigger('input');
scope.$digest();
expect(element.val()).toBe('12345');
});
it('should not accepts input value if it is not number', function(){
element.val('not a number');
element.trigger('input');
scope.$digest();
expect(element.val()).toBe('');
});
it('should reject other than numbers', function(){
element.val('%$#$%%%^123456789not a number');
element.trigger('input');
scope.$digest();
expect(element.val()).toBe('123456789');
});
});
Upvotes: 0
Reputation: 5526
Taken from the video in Acosta's comment:
The way to make angular do its thing is to trigger the 'input' event on the element (using element.trigger('input')
. So in your test, you should be able to do:
element.val("10k");
element.trigger("input");
element.scope().$apply(); //not sure if you even need to do this, video says yes, however on angular 1.3.8 I didnt need to
expect(element.val()).toBe('10000');
expect(element.scope().Amount).toBe('10000');
Upvotes: 3