Angular prevent setting model to undefined on invalid - javascript

When validation fails on an input, the model is being set to undefined. Is there a way to prevent this. I'm on Angular version 1.4.8.
E.g.
<input id="name" ng-model="inputname" minlength="4">
When I insert some value here and then reduce it to less than 4 characters the model inputname becomes undefined.

Figured this out, there is an option under ngModelOptions called allowInvalid which allows the modelValue to be updated with the viewValue even if it is invalid (instead of the default behaviour of setting it to undefined).
From the documentation:
allowInvalid: boolean value which indicates that the model can be set with values that did not validate correctly instead of the default behavior of setting the model to undefined.

Related

In Redux Form, how can I set the initial value of the checked property of a checkbox?

In our Redux Form 5.3 (not 6.x) app, I want to render an <input type="checkbox" /> like so:
// In some cases, fieldHelper.checked is initially undefined. Then, when the
// user clicks one of the checkboxes, fieldHelper.checked is
// explicitly set to true or false. This change from one of the component's
// props being undefined to having a value causes a React warning; see
// http://stackoverflow.com/a/38015169/473792 and
// https://facebook.github.io/react/docs/forms.html#controlled-components
// So to prevent that warning, we do a quick null check on
// fieldHelper.checked and replace it with false explicitly if it is
// undefined before rendering the checkbox.
const fieldHelper = this.props.field['checkbox'];
const checked = fieldHelper.checked || false;
const modifiedFieldHelper = Object.assign({}, fieldHelper);
delete modifiedFieldHelper.checked;
return (
<input
checked={checked}
{...modifiedFieldHelper}
/>
);
}
As noted in the comment, in my testing environment, this.props.field['checkbox'].checked is undefined immediately after mounting the <input>. As a result, when my tests modify the value of this.props.field['checkbox'].checked, I get the following warning:
Warning: ApplicantForm is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
... Unless I explicitly set the checked prop on the <input> to false instead of undefined, as demonstrated in the code snippet I posted above.
Instead of using this null check, I would like to set the initial value of this.props.fields['checkbox'].checked before my tests run. I know I can set the initial value of fields in Redux Form. Is there a way to set the initial value of an auxiliary property like the checked property that Redux Form also controls?
You could create a simple conditional in your checked attribute so that when the value is undefined you just return false:
<input
type="checkbox"
checked={typeof this.props.fields['checkbox'].checked == 'undefined'?false:this.props.fields['checkbox'].checked}
onClick={() => {... your onClick code ...}} />
Checkboxes are no different from text inputs. You can still just destructure the field object into your <input>. See how the employed value is used in the v5.3.3 Simple Form Example.
<input type="checkbox" {...myField}/>
Redux Form will detect that it's a checkbox (really it detects for boolean values) and use the checked prop.
I've never used Redux-Form but to display the default checked value for a checkbox in default React you'll need to use the defaultChecked attribute. It accepts a boolean.
<input type="checkbox" defaultChecked={/*bool*/} />

Changing `ng-required` calls `ng-change`

I have a strange behavior in my app using AngularJS 1.5.8:
plunker (https://plnkr.co/edit/zaHVJeK8hdxk2gaOL9Pf?p=preview) and video(http://recordit.co/eszvfdfC9S)
step 1. At the beginning changing ng-required doesn't call ng-change function
step 2. After making changes in input AND removing them (input is empty) ng-required DOES call ng-change function
expected behavior?
step 2. After making changes in input AND removing them (input is empty) ng-required SHOULD NOT call ng-change function. As it was at the beginning, and as it is when input has some value
Please let me know if it's a bug or not. If not then why changing ng-required calls ng-change NOT always or even at all?
ANSWER IS FOUND-------------------------------------------------------------------------------------------------------
NgModelController has two properties: $viewValue (value entered by
user) and $modelValue (value bound to your model). When the value
entered by the user fails validation, NgModelController sets the model
to undefined.
In AngularJS 1.3, they added the ng-model-options directive. It lets you
configure how/when the model gets updated. You can use the
allowInvalid option to prevent your model from being set to undefined:
ng-model-options="{allowInvalid: true}"
You should add
ng-model-options="{allowInvalid: true}"
So the final result will be
<input type="text"
ng-change="$ctrl.onChange()"
ng-required="$ctrl.isRequired"
ng-model-options="{allowInvalid: true}"
ng-model="$ctrl.val"
/>
This is happening because the ng-required is changing the attached modal value to undefined from blank when the required is set to false, due to this ng-change is fired since the modal changes.
Check in the plunker i have console.log the value of input and you can see the change of modal clearly.
angular.
module('myApp', []).
component('greetUser', {
templateUrl: 'tmpl.html',
controller: function GreetUserController() {
this.output='';
this.isRequired = false;
console.log(this.val);
this.onChange = function() {
console.log(this.val);
this.output+='Changed\n';
}
}
});
plunker : https://plnkr.co/edit/6IeIjIDahcmBIU4KSASJ?p=preview
Now the question arises that why not the on load/ first time the change event is not firing up that is because we are using this object rather then $scope.
Here
'this' vs $scope in AngularJS controllers
is a very good example which explains why until we manually enter the value in the input at least once the change event is not firing up.
in short this is happening because ng-change/ng-model works with scope variables. Once you manually enter value in the input element, the model binding happens with the scope, and the ng-change event start firing up.
I think you misunderstanding.
ng-required and ng-change is different things. doing different purpose, and not calling each other.
ng-change is calling your function no matter what it's empty or not. It's call your method by it self, regarding to changes happening in the input.
ng-required is just checking value if it's empty or not, If it is empty, mark it as invalid.
In order to get what you want, you have to check the validity inside the onChange function.
this.onChange = function() {
if( !$scope.$ctrl.form.$valid ) return;
this.output+='Changed\n';
}
I think this is the reason. put an alert inside ng-change like this.
this.onChange = function() {
alert(this.val);
this.output+='Changed\n';
}
When you empty the box after completing it the value change between two values:
undefined when is required
'' when is not required
So By changing the radio box you call the ng-change,
At the beginning you have
However when you have not started to type in the text box , radio box does not change the input value , because ng-change is for input. In the beginning we have undefined --> undefined so nothing changed. then when you empty the input you have '' ---> undefined.
Actually if you put this in your controller you get call ng-change at the beginning too.
this.val ='';
So if you replace your controller with this , you see ng-change is called even at the beginning.
angular.
module('myApp', []).
component('greetUser', {
templateUrl: 'tmpl.html',
controller: function GreetUserController() {
this.output='';
this.isRequired = false;
this.val ='';
this.onChange = function() {
this.output+='Changed\n';
}
}
});

Watch ng-model whilst using minlength?

I'm trying to watch the value of ng-model whilst also using the minlength validation. The problem is the model value remains empty/undefined until the validation criteria is met.
HTML
<input ng-model="xyz" minlength="8" />
JS
$scope.$watch('xyz', function(val) {
// Will either be undefined or a
// string bigger than or equal
// to 8 characters.
console.log(val);
});
I know I could just substring the element's value, but this code is implemented in a directive which uses $compile, so ideally I'd prefer to watch the model value.
Any thoughts on how to resolve this?
https://docs.angularjs.org/api/ng/directive/ngModelOptions
allowInvalid: boolean value which indicates that the model can be set with values that did not validate correctly instead of the default behavior of setting the model to undefined.

How to edit/delete all text on an required field in AngularJS

While editing an angular textbox marked as "required", I am unable to delete the 1st letter. However if I move my cursor to before the 1st letter, and enter some text and then delete the last letter left earlier, I am able to do my required edit.
Note: No such issue being observed while creating a new record.
Please find the sample code being used.
<input type="text" class="form-control" ng-model="vm.xyz.firstName" ng-model-options="modelOptions" required />
Used library version: angular: 1.3.15, bootstrap:3.3.2
Thanks in advance.
This is the expected behaviour as per documentation:
If the validity changes to invalid, the model will be set to undefined, unless ngModelOptions.allowInvalid is true.
Since you set your field as required, when it becomes empty, it becomes $invalid, which in turn sets your model to undefined. If you add allowInvalid: true to your ngModelOptions settings, your model will be allowed to receive the empty string value instead of undefined. Plunkr here.
As described by #leonardo-braga, this happens because the field becomes invalid upon deletion of the last character and the $modelValue set to undefined (which tricks your getter/setter into believing it has been called in "getter" mode).
A similar question has been answered on GitHub.
Copying here for easier reference:
Using allowInvalid will work around the issue, but it is not solving the actual problem.
The actual problem lies in the implementation of the getter/setter function, which treats passing an argument with value undefined as passing no argument at all (although these are obviously two very distinct cases).
You should use a more "accurate" way of defining whether the function is called as a getter or as a setter (i.e. whether an argument has been passed (even if undefined) or not).
E.g.:
getterSetterFn: function (newValue) {
if (arguments.length) {
_value = newValue;
}
return _value;
}
See, also, this short demo.

Ember.js checkbox binding initial value set incorrectly

Somehow the checkbox in my Ember app is always initially checked.
...
{{#each model.fields}}
...
{{input type="checkbox" checked=isOptional}}
The fields array is an attribute in my model. Each object in fields array has an attribute called isOptional, which can be "true" or "false".
For some reason, regardless of the value of isOptional, the checkbox is initially checked.
If I check the checkbox manually, the isOptional flag will actually be changed. So the binding works except for detecting the initial value.
Any help is much appreciated, thanks!
Edit: As discussed in comments, the problem was because my model was returned by Ember.$.getJSON(), which has "false" in quotes and was interpreted as true value, resulting in checked checkboxes. I resolved this by over-writing the boolean values:
model.fields.forEach(function(field, i) {
Ember.set(field, 'isOptional', (field.isOptional == 'true'));
});
A jsbin example you can fiddle with
http://emberjs.jsbin.com/kukokiti/1/
If you can provide your own jsbin, we can help out more.
EDIT: You can see the effects of the 'false', in a string value.
The easiest way might be to define a computed property on the model you are using.

Categories