I'm running into a strange issue in Firefox that I hope someone can explain to me. I have an AngularJS controller with a method that is tied to ng-change on a variety of input controls in a form, including one that is marked as a number input. The logic of this method is that if any one of the bound scope variables is set properly, to set another scope variable to true. This is basically an attempt at form validation where any one (or more) of the inputs is required.
Example:
app.controller('test', function($scope) {
$scope.num = 0;
$scope.name = "";
$scope.valid = false;
$scope.inputChange = function() {
console.log('Input changed');
$scope.valid = ($scope.num > 0) || ($scope.name.length > 0);
}
});
And form:
<form name="numberTest" ng-app="myApp" ng-controller="test">
<input ng-model="name" name="name" type="text" ng-change="inputChange()"/>
<input type="number" ng-model="num" name="n" id="n" ng-change="inputChange()"/>
<input type="button" value="Go" ng-disabled="!valid"/>
</form>
This all works fine in Chrome, but in Firefox this ng-change handler is fired when non-numeric text is entered in the numeric input and the textbox itself does get this bogus data in it although the model is not updated. This leads to a confusing state where there is invalid data in the num textbox that is not bound to the AngularJS model but the user can click the button. Chrome does not present this problem as it does not render the non-numeric data in the input control.
How can I detect (and handle) this scenario? The input control is displaying text that is invalid and not bound to the binding model.
I am certainly open to alternative implementations to achieve this same effect. AngularJS version is 1.3.0.
Example plunker to run in Firefox to see the "bad" behavior
I ended up discovering the $valid attribute of these number inputs, and that seemingly satisfies my needs:
Returns true if empty
Returns false if non-numeric data is in the control
So, my updated button:
<input type="button" value="Go" ng-disabled="!valid || !numberTest.n.$valid"/>
Related
I'm trying to impliment some CRUD page with AngularJS. So i have input with some validation requirements
<input ng-class="addForm.country.$error.pattern?'bad-input-border':''"
name="country"
ng-model="adding_element.country"
type="text"
pattern="[A-Za-z]+"
class="form-control">
Pattern that match only letters.
Also i have bingding model with that input.
The problem is: when i change input value directly on page, validation works fine addForm.country.$valid == true; but when i'm trying to change my model from code i get addForm.country.$valid == false even if data is valid.
I changing model on button click, that get generated element from my controller:
$scope.generate_country = function()
{
$http.get("/index.php/cars/generate").then(function(response){
$scope.adding_element.country = response.data.item.Country;
});
};
The result in response.data.item.Country is string. It fails input pattern when i click the button, but when i CTRL+C CTRL+V generated result in input it's OK.
How can i solve that? TIA!
Im trying to be as ellaborative as i can with my question....
Scenario:
I have three input fields in my html page Two of them are to accept user inputted values and the third one binds(adds) these two values.
Done so far:
I initially used <input value="{{value1+value2}}" id="value3"/> which took the values as string; solved this issue by substracting the string by 0. But, this calculated values wont go off even using the reset button.
Then someone here on SOF told me to use <input ng-model="(value1-0)+(value2-0)" id="value3"/> which works, but i noticed that even though the values disapper visually the model still holds some value.
(When, i enter some value into the first input field, the third calculated field add the value of the inputted field with the previous value of the second input field(value that the second field had previous to the reset)
NOTE:
Reset method resets the values of the first two user inputted fields, but not that of the third calcualtion field while using <input value="{{value1+value2}}" id="value3"/> OR <input ng-bind="value1+value2" id="value3"/>
While, when using <input ng-model="(value1-0)+(value2-0)" id="value3"/> the calculated field is visually cleared but when i enter some value into one of the user inputted fields(value1 or value2) the calculated field adds the entered number with the previous number that the field ccontained.
I tried many ways to solve this issue, but with no suuccess.... can someone please guide me through?
Thanks in advance.....
Here's a simple fiddle . Follow the link and take a look.
Basically, to have only number values in the user inputed fields, I used HTML5 number inputs, readily available in any newer browser.
<div ng-controller="MyCtrl">
<input type="number" ng-model="value1" />
<input type="number" ng-model="value2" />
<input type="text" ng-model="value1 + value2" />
<button type="button" ng-click="reset()">RESET</button>
</div>
And as for the javascript, here is my controller:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', MyCtrl)
function MyCtrl($scope) {
$scope.value1 = '';
$scope.value2 = '';
$scope.value3 = '';
$scope.reset = function() {
$scope.value1 = '';
$scope.value2 = '';
$scope.value3 = '';
};
}
The three values are first initialized as empty strings, and on ng-click of the RESET button, they are nullified again.
NOTE: For the sake of simplicity I used number inputs instead of trying to implement some kind of javascript validation which I would suggest for production level. The point of my answer was just to explain the principle using the most basic concepts.
JSfiddle code at the bottom
My problem: If an <input> field has whitespace in it and you "clear" the value with angular by setting its scope value to an empty string, it leaves the whitespace in the input field.
The reason: I understand why it is doing it, as the angular digest doesn't see a change, since it already has the scope variable empty due to trimmed whitespace via ng-trim.
My question: Is there a proper way to make sure the input field gets blanked out? I know of multiple solutions, but all of them are hacks or wouldn't work.
Set the scope value to null, and then to blank after a $timeout. But this could cause problems due to the code expecting only strings in the scope value.
Set the element to ng-trim, but I like having the value automatically trimmed
Empty the input field with jquery (or directly setting the element's value). This is probably the solution I am going to end up going with (a function that clears the input and blanks the scope variable at the same time), but I'm hoping there is something not quite so hacky.
jsfiddle: https://jsfiddle.net/0kf84g5o/3/
HTML
<div ng-app=MyApp>
<div ng-controller="TestCtl">
Press "tabs and spaces", add spaces and/or tabs, and then press "blank out'<br>
<input ng-model=TestInput id=TestInput>
<input type=button value="abc" ng-click="ChangeTestValue('abc')">
<input type=button value="Tabs and spaces"ng-click="ChangeTestValue('\t \t')">
<input type=button value="Blank out" ng-click="ChangeTestValue('')">
<input type=button value="Null out" ng-click="ChangeTestValue(null);">
<pre>
Angular Value: --{{TestInput}}--
JSONified Angular Value: --{{TestInputJSON}}--
Actual input value JSONified: --{{TestInputActualJSON}}--
</pre>
</div>
</div>
Javascript
var MyApp=angular.module('MyApp', []);
MyApp.controller('TestCtl', function($scope, $timeout) {
//Update the value programatically
$scope.TestInput='Start text';
$scope.ChangeTestValue=function(Str) {
$scope.TestInput=Str;
};
//Update TestInputJSON
$scope.$watch('TestInput', function(NewVal) { //When angular values changes
scope.TestInputJSON=JSON.stringify(NewVal);
});
//Update TestInputActualJSON
$scope.$watch('TestInput', function(NewVal) { //When angular value changes
$timeout(UpdateTestInputActualJSON, 1); //Wait for 1ms to update so the new value is alread set
});
$('#TestInput').on('keyup paste', UpdateTestInputActualJSON); //On a jquery event
function UpdateTestInputActualJSON(e) //Do the actual update of TestInputActualJSON
{
$scope.TestInputActualJSON=JSON.stringify($('#TestInput').val());
if(e) //Call angular digest if coming from jQuery
$scope.$apply();
}
});
Angular validation currently works by updating on model change. Although displaying these validation errors upon keyup is not very UI friendly.
An ideal solution would be to display the error messages on blur, along with on form submit. Once an input is blurred on the first time and an error message is displayed, the input would then need to be updated on keyup/model change.
I have seen the following which allows the model to be updated upon blur, but this is not an ideal solution since the model is only updated on blur for every situation.
<input type="text" name="user" ng-model="user" ng-model-options="{ updateOn: 'blur' }" required>
I also came across the following solution that works well on blur and then changes to keyup after an error exists. Although the validation does not apply on form submit.
http://plnkr.co/edit/VSPOYO16ozq2bKaLl3n9?p=preview
Here for this you can have one angular scope variable which maintain the state of form submit is submitted or not by default that variable is false.
$scope.submitted = false;
and one scope function which validate the fields on form submit. Keep in mind place name attribute of form element is must be stetted and refereed same in function. Function approach is to make it generic. You can directly write into html template also by accessing $dirty and $error variable of that input elements.
$scope.validateInput = function (name, type) {
var input = $scope.demoform[name];
return (input.$dirty || $scope.submitted) && input.$error[type];
};
This is function which will be called on form submission.
$scope.submitForm = function () {
$scope.submitted = true;
if ($scope.demoform.$valid) {
console.log('Submitted!!');
} else {
console.log('Not valid!!');
return false;
}
};
Now on html template you can write this way .
<form name="demoform" ng-submit="submitForm()" novalidate="">
<input type="text" name="name" required="" ng-model="name"/>
<span ng-show="validateInput('name', 'required')" class="text-danger">Name is required</span>
<button type="submit" class="btn btn-info" >Save</button>
</form>
Now on form submit You can see the validation message is there if field is not valid.
Demo Plunkr of form validation on form submit in angular
Create a directive that is bound to the blur event, you seem to have found one that will work but I can't read the Plunkr on my phone, and use this to set validity.
Now inside your submit function in the controller you need to check the form for errors.
if (Object.keys($scope.formName.$error).length > 0) {
return false;
}
is an easy way to do this and will also still have the form set to $submitted.
Using jQuery, I change the value of an input text field through some process. After the process is done, I need to capture this change and apply it to another process. My problem is that I can't seem to capture this change and assign it to a variable. I know the changes are happening because the DOM is getting updated. Furthermore, this variable assignment works in IE, but not for the other browsers I tested.
Below is a snippet to prove my point (and you can see this online here: http://jsfiddle.net/xMwAE/).
<form>
<input type="hidden" name="my_hidden" value="Hidden Field" />
<input type="text" name="my_text" value="Text Field" />
</form>
$().ready(function() {
$('input[name=my_hidden]').val('Hello Hidden Field');
$('input[name=my_text]').val('Hello Text Field');
// Display
var temp = $('form').html();
// Though the DOM is updated with the new values. The variable temp
// does not capture the changes to the input text field, but captures
// the change in the hidden field. When in IE, temp captures the
// changes in both fields.
alert(temp);
});
Obviously, I need consistent behavior across browsers. Any ideas what's going on?
I don't get any trusted idea what happens, but somehow there should be a difference between setting the value as a member (input.value) or setting the value as a attribute-node.
This works for me :
$('input[name=my_text]').each(function()
{ this.setAttribute('value','Hello Text Field');});
I guess its a bug in innerHTML, see bugzilla: https://bugzilla.mozilla.org/show_bug.cgi?id=535992
Alternatively, you can store the values of your fields into array and use however you like like this:
var data = [];
$('form :input').each(function(){
data.push(this.value);
});
Now you can check for values like this:
alert(data[0]);
alert(data[1]);