maxlength on field not working with Karma - angularjs

I have a field with a maxlength of 6, but somehow the following way of entering data results in 7 chars being allowed:
<input type="text" name="myName" maxlength="6" ng-model="myModel">
this is the test bit:
input('myModel').enter('1111117');
expect(input('myModel').val()).toBe(111111);
and this is the result
expected 111111 but was "1111117"
I suppose this has to do with the model being used instead of the real field, but how would I test this then in Karma?

The problem is caused because maxlength only limits the input from the user, and not the actual value of the input. For example, if you try to use jQuery's val() on your input, it would accept any length of the value.
I tried to simulate input in more sophisticated ways, like triggering keyboard events or third party tools, but with no success. It looks like any programmatic way to change the input's value, is not limited by maxlength.

I know this is an old question, but this may be helpful to someone with the same problem.
In my case I just checked the the value length of the input manually, in the function used to set the input value:
function insertKey(input: HTMLInputElement, key: string) {
input.dispatchEvent(new KeyboardEvent('keydown', {key: key}));
if (input.value.length < input.maxLength) {
input.value += key;
input.dispatchEvent(new KeyboardEvent('change', null));
}
input.dispatchEvent(new KeyboardEvent('keyup', {key: key}));
}

Related

Angular can I have 2 ng-pattern to validate the same filed

My current input looks like this
<input type="email" name="email"
ng-pattern="emailRegex"
ng-change="emailChanged()"
required />
My ng-pattern="ctrl.emailRegex" validates if an email is valid or not
/^[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{1,63}$/;
But I would like to block info#, admin#, help#, sales# emails, so I changed the regex to
/^(?!(?:info|admin|help|sales)#)[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{1,63}$/
So far so good, but I would like to show
Invalid email
to "invalid#!!!!!.com!"
and
info#, admin#, help#, sales# emails are not allowed
to info#test.com
How can I have 2 ng-pattern in the same input?
Thanks
You can validate only one pattern for an input. And, even if you can sort of do it somehow by using a directive, it would be too dirty a solution. Instead, I would recommend validating the input against regex(es) inside the function of ng-change and use formName.inputName.$setValidity to set custom validity of the input. This lets you have a fallback if one pattern is passed.
So, for example, ctrl.emailChanged could probably have something like this,
ctrl.emailChanged = function() {
var emailPattern = /^[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{1,63}$/;
var customValidateEmail = /^(?!(?:info|admin|help|sales)#)[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{1,63}$/;
if(!emailPattern.test(ctrl.registrationForm.email)) {
// Invalid email
} else if (customValidateEmail.test(ctrl.registrationForm.email)) {
// handle accordingly
}
// rest of the things
...
}
Alternatively, you can move the validation logic to another function and just call it from emailChanged.

Replace , with . in input field bound to property using Angular 1

I have an input field that is supposed to contain numbers.
It is bound to an object property.
I want input entered as 4,5 to automatically get converted to 4.5 in both model and view.
HTML:
<input data-ng-model="productContent(product.Id).Org" value="{{productContent(product.Id).Org | replaceComma}}" />
Control:
$scope.productContent = function (prodId) {
var content = $.grep($scope.productsContent, function (el) { return el.ProdId === prodId });
return content[0];}
Filter:
app.filter('replaceComma', function () {
return function (val) {
return (typeof val) == "string" ? val.toString().trim().replace(",", ".") : val
};
});
Result:
When I enter a number, at first the model (productContent) retrieves the correct object. Then the filter code is called and returns a correctly converted string. I would expect both the model and view to be updated to the filtered value, but both are updated with the unfiltered value. What am I doing wrong?
I have faced the same problem in the past but instead of creating my own filter, I took a different path and found something ready to use instead.
angular-input-masks by assisrafael one of my favourite angular extensions for this purpose:
https://github.com/assisrafael/angular-input-masks
Examples:
http://assisrafael.github.io/angular-input-masks/
Since the author has written the documentation, I don't want to get extensive on it and be outdated in the future. As a quick reference, look for ui-number-mask.
Maybe this is not a direct answer to your question, since it's not replacing commas with periods, but making you type the decimals instead.
On a side note, you can suppress the thousands separators with ui-hide-group-sep
I hope that's helpful, otherwise leave a comment and I'll be happy to continue to assist you!
-Helvio

Input is invalid even when it's error is empty

I'm trying to create my own validation for password confirm, and putting my error on $error. this is my code:
html:
<input ng-model="user.password2" type="password" name="password2" required
ng-keyup="confirmPassword(user.password, user.password2)">
<div ng-messages="register.password2.$error" ng-if="register.password2.$dirty">
<div ng-message="required">Password is required</div>
<div ng-message="passwordsDontMatch">Passwords don't match</div>
</div>
JS:
$scope.confirmPassword = function (pass1, pass2) {
if (angular.isUndefined(pass1) || angular.isUndefined(pass2) || pass1.trim() != pass2.trim()) {
$scope.register.password2.$error["passwordsDontMatch"] = true;
} else {
delete $scope.register.password2.$error["passwordsDontMatch"];
}
console.log($scope.register.password2.$error);
};
it looks like it's working. when the passwords are the same, the message is not displayed and indeed the $error object is empty. But the input is still invalid: ($scope.register.password2.$invalid == true)
you can see what I'm talking about in this plunkr: http://plnkr.co/edit/ETuVqsdSaEBWARvlt4RR?p=preview
try 2 identical passwords. the message will disappear but when you blur from the input, it's still red because internally it's $invalid
The problem probably comes from the fact that you're not typing a password in the first field that matches your regex pattern. The first password is thus undefined, since it doesn't respect the ng-pattern validation rule.
That said, you shouldn't modify the $error array directly. Instead, you should set the validity of the field using $setValidity(). That will not only set and remove the error automatically, but also deal with the $invalid/$valid properties, add and remove the CSS classes, etc.
var valid = !((angular.isUndefined(pass1) || angular.isUndefined(pass2) || pass1.trim() != pass2.trim()));
$scope.register.password2.$setValidity("passwordsDontMatch", valid);
Here's a working example. But remember to enter a valid password in the first place.
Also, instead of implementing this check with ng-keyup, you should make it a directive, which would add a validator to the validators of the form input. This would make sure the check is made whatever the way the second password is entered (i.e. via copy/paste using the mouse only, or simply by prepopulating the form programmatically.

Issue on prepopulating model value on view init in angularJS

I want to prepopulate an input field from my controller:
Here is the input field:
<input class="form-control" type="text" name="partnerName" placeholder="Completeaza numele partenerului" ng-model="partnerNameModel.field" required validate-field="partnerNameModel">
In my controller,
If I do this:
partnerNameModel.field = 'test';
I get the following error:
TypeError: Cannot set property 'field' of undefined
So, I had to do it like this:
$scope.partnerNameModel = {field: 'dsad'};
I this good practice?
Is there a better way to prepopulate fields?
You can create the object partnerNameModel by doing
$scope.partnerNameModel = {}
at the top of your controller then you can use the dot syntax to set values like
$scope.partnerNameModel.value = "foo"
$scope.partnerNameModel.bar = "lemons"
This is how I personally work with objects in Angular
When you are dealing with an input that has a placeholder, it makes sense to put no default value.
However, the object you are using must be created or it will be a big pain in the ass.
I recommend that you simply use:
$scope.partnerNameModel = {};
Make sure to initialize your fields that don't use a non-empty default value (a dropdown as an example).
$scope.partnerNameModel = {
myDrop: $scope.myList[0]
};

edit in ng-grid not working for numeric type

I have implemented a ng-grid..but edit functionality is not working properly...Its designed in such a way that one column's inupt type is numeric i.e
$scope.cellInputNumericTemplate = '<input type="number" ng-input="COL_FIELD" ng-
model="COL_FIELD" ng-class="\'colt\' + col.index">';
if(childtemp.fieldType=='Long' || childtemp.fieldType=='Double') {
$scope.templateColumnDefs.push({field:childtemp.name, enableCellEdit:true,
editableCellTemplate:$scope.cellInputNumericTemplate});
}
$scope.gridOptions = {
enableCellSelection: true,
enableCellEdit: true,
columnDefs: 'templateColumnDefs'
//some other features as well included
}
now i have other columns with type as string,date..etc and they are working perfectly fine but in case of this double and long i am able to enter the value the very first time but if i try to modify the value its not allowing me to do it..i.e edit is not working for that colum alone...
can someone plz help..
Input type "number" doesn't work in Firefox until version 28+ (if it shipped in that).
You can make the field a text field, and add a controller to it that watches the model. If the new value is not a number, don't allow it by setting the model value back to old value. Putting this in ng-grid adds a bit of complexity but it's probably do-able if you are persistent.
$scope.$watch('model', function(newValue,oldValue) {
if (!newValue)
return;
var arr = String(newValue).split("");
if (arr.length === 0)
return;
if (isNaN(newValue)){
$scope.model = oldValue;
}
});
I am not sure if you want to say that the number cant be changed with up/down buttons.
In that case you also need to add step parameter to your input that changes with a lower rate than the default 1.
<input type="number" step="0.01">...
Look at this Plunker
That what you wanted?
Another way to increment without using floating point steps would be:
step="any"
Just play around with the plunker.

Resources