I've been trying to grab hold of the Angular forms applying best practices for form validations, that forced me to use the form name and have all of the models as children of it so that I can bind the formname.$valid and all the other stuff.
However I haven't been able to set predefined values to any of the form sub models as I have no access to them in the controller.
My biggest problem right now is how to check for falsy checkboxes because initially the checkbox is unchecked but there is no value, it only gets populated when clicked to change the value.
Here is my form code
<form name="addAppForm" ng-if="creatingApp == false">
<input type="text" placeholder="App Name" required autofocus ng-model="addAppForm.appName">
<input icheck id="ios" type="checkbox" ng-init="addAppForm.iOS = false" ng-model="addAppForm.iOS">
<label for="ios"><i class="icon-apple"></i> iOS {{addAppForm.iOS}}</label>
<input icheck id="android" type="checkbox" ng-init="addAppForm.android = false" ng-model="addAppForm.android">
<label for="android"><i class="icon-android"></i> Android {{addAppForm.android}}</label>
<button ng-disabled="addAppForm.$invalid && (addAppForm.iOS != true && addAppForm.android != true)" type="submit" ng-click="addNewApp(addAppForm.iOS, addAppForm.android, addAppForm.appName)" class="button front-primary large radius expand">Let's GO!</button>
</form>
The "required" directive doesn't apply to the checkboxes and I've tried initializing the model but with no luck.
When you add a named form like that, it is added to your controller's scope. You can access it inside the controller using the name, similar to in the HTML:
$scope.addAppForm.android;
This should evaluate to true/false any time after the form has been set up, even if it hasn't been clicked yet.
Edit: Fiddle where form is accessed in the controller.
I've figured out what's wrong with my code, the ng-init actually works, I just mixed up the operators here -->> ng-disabled="addAppForm.$invalid && (addAppForm.iOS != true && addAppForm.android != true)"
Should have been ng-disabled="addAppForm.$invalid || (addAppForm.iOS != true && addAppForm.android != true)"
Still the problem persists of not being able to access the form from the controller not even in the same view outside of the form.
I still don't understand why u have to save your data in the Formcontroller u can use a object ( here i call it 'model' ) and put all your form values inside. Your Formcontroller object ( 'addAppForm' ) has functionality and saves validation errors see here : https://docs.angularjs.org/api/ng/type/form.FormController This object is added to the scope of your Controller late in the initialisation of your Controller
see: https://docs.angularjs.org/api/ng/directive/form
Directive that instantiates FormController.
If the name attribute is specified, the form controller is published onto the current scope under this name.
Here is the way to have the form invalid if not at least one checkbox is selected
var myApp = angular.module("myApp", []);
myApp.controller("myController1", function($scope) {
$scope.model = {
"ios": false,
"android": false
};
});
<div ng-app="myApp" ng-controller="myController1">
<form name="addAppForm">
<input type="text" placeholder="App Name" required autofocus ng-model="model.appName" />
<input id="ios" name="ios" type="checkbox" ng-model="model.ios" ng-required="!model.ios && !model.android" />
<label for="ios"><i class="icon-apple"></i> iOS</label>
<input id="android" name="android" type="checkbox" ng-model="model.android" ng-required="!model.ios && !model.android" />
<label for="android"><i class="icon-android"></i> Android</label>
<button ng-disabled="addAppForm.$invalid " type="submit" ng-click="addNewApp(model.ios, model.android, model.appName)" class="button front-primary large radius expand">Let's GO!</button>
</form>
</div>
<script src="https://code.angularjs.org/1.3.8/angular.min.js"></script>
Related
when user click on submit button i am validating form, using ng-click i am calling function, in this function i am passing form1.$invalid,based on this variable , i am putting condition, if condition true, validate function will call, here problem is mobile is hidden field, this hidden field also checking validation.how can skip or not validate mobile field hidden status, I tried bellow code.
html
----
<form name="form1" novalidate>
<input ng-show="user" type="text" name="user" ng-model="frm1.user" />
<p ng-show="form1.user.$error.required"><span ng-show="errorMsgShow" ng-required="true">{{requiredMsg}}</span></p>
<input ng-show="mobile" type="text" name="mobile" ng-model="frm1.mobile" />
<p ng-show="form1.mobile.$error.required"><span ng-show="errorMsgShow" ng-required="true">{{requiredMsg}}</span></p>
<button ng-click="SubmitForm(regForm.$invalid);">submit</button>
</form>
Script----
$scope.SubmitForm = function(val){
$scope.user= true;
$scope.mobile = false;
if (if(val ===true){
$scope.validation();
}
}
$scope.validation = function(){
$scope.requiredMsg="input fieldis required";
}
I suggest better approach will be taking the mobile input out of the form when it's unnecessary using ng-if rather than just hide it with ng-show.
Ng-if will make sure the input is not rendered in the DOM tree when the condition is false, therefore, there will be no validation triggered.
You can do some research on differences between ng-if and ng-show to have better understanding about these two directives.
Try ng-if to avoid validation.If you want mobile to skip validation then make ng-if as false using expression.
syntax: ng-if="expression"
go to this link for further info
https://docs.angularjs.org/api/ng/directive/ngIf
for difference between ng-if and ng-hide/ng-show refer the below link
what is the difference between ng-if and ng-show/ng-hide
Some observations :
Instead of using ng-show to hide and show the inputs just use <input type="hidden"... > element for mobile field.
No need to use variable $scope.user and $scope.mobile to hide and show the inputs.
Add the required attribute in the user input field not on mobile input field as you don't want to validate mobile field.
Use SubmitForm(form1.$invalid) instead of SubmitForm(regForm.$invalid) as your form name is form1 not regForm.
DEMO
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
$scope.SubmitForm = function(val) {
console.log(val);
if(val === true) {
$scope.validation();
}
}
$scope.validation = function() {
$scope.requiredMsg="input fieldis required";
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<form name="form1" novalidate>
<input type="text" name="user" ng-model="frm1.user" required/>
<p ng-show="form1.user.$error.required">{{requiredMsg}}</p>
<input type="hidden" name="mobile" ng-model="frm1.mobile" />
<button ng-click="SubmitForm(form1.$invalid);">submit</button>
</form>
</div>
I know how to pass a value from a view to a controller using ng-model. In the controller it just gets the value from the view using this code $scope.name = this.ngmodelnameinview.
Is it compulsory to use ng-model in field view?
but my problem now is, I have + button, which when I click the button it will automatically put the value inside input text field.
<button data-ng-click="adultCount = adultCount+1"> + </button>
<input type="text" name="totTicket" value="{{adultCount}}">
see picture below:
but when I add ng-model inside input field, it returns null
<input type="text" name="totTicket" value="{{adultCount}}" ng-model="adultcount">
How to fix this? Thanks!
It is giving null just because you have set a value "adultCount" and in ng-model you had given a different name "adultcount" ('c' is in lower case). By updating ng-model with "adultCount", will solve this issue.
JavaScript is case sensitive:
JavaScript is case-sensitive and uses the Unicode character set.1
Use the same case for the scope variable. Update the input attribute ng-model to match the varible - i.e.:
<input type="text" name="totTicket" value="{{adultCount}}" ng-model="adultcount">
should be:
<input type="text" name="totTicket" value="{{adultCount}}" ng-model="adultCount">
<!-- ^ -->
See this demonstrated in the snippet below:
angular.module('app', [])
.controller('ctrl', function($scope) {
//adultCount could be initialized here
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<button data-ng-click="adultCount = adultCount+1"> + </button>
totTicket:
<input type="text" name="totTicket" value="{{adultCount}}">
totTicket (adultCount):
<input type="text" name="totTicket" value="{{adultCount}}" ng-model="adultCount">
</div>
——
1https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types
I create a form dynamically in the view by iterating through an object that has the different questions to be asked to the user. One of the attributes of every question is formFieldName which is a a random string I use to give each form field a different name.
<form name="includedForm.newRequestForm" class="form-horizontal" role="form" novalidate>
<div ng-if="message.question.attributes.structure.type == 'object'">
<div ng-repeat="(index,objField) in message.question.attributes.structure.properties">
<div ng-if="objField.type == 'array'" class="form-group" show-errors>
<label for="{{objField.formFieldName}}" class="control-label col-sm-6">{{objField.title}}
<br /><i><small>{{objField.description}}</small></i></label>
<div class="col-sm-6">
<select class="form-control" name="{{objField.formFieldName}}" multiple ng-model="objField.userValue" ng-required="objField.required">
<option ng-repeat="option in objField.items.enum" value="{{option}}">{{option}}</option>
</select>
</div>
</div>
<div ng-if="objField.type == 'boolean'" class="form-group" show-errors>
<label for="{{objField.formFieldName}}" class="control-label col-sm-6">{{objField.title}}</label>
<div class="col-sm-6">
<input class="form-control" name="{{objField.formFieldName}}" ng-model="objField.userValue" type="checkbox" ng-value="option" ng-checked="message.question.attributes" />
</div>
</div>
</div>
</div>
<div class="col-sm-12">
<button ng-click="markAsDone(message)" class="btn btn-primary">Done</button>
</div>
<form>
In the controller I'm able to get the formFieldName attribute but I can't figure out how to use it to do the validation.
var MarkAsDone = function(message) {
$scope.includedForm = {};
var formField = message.question.attributes.formFieldName;
if ($scope.includedForm.newRequestForm.{{formField}}.$valid){
//submit the form
}
}
to answer you question:
first, {{}} is === $scope so you don't use that anywhere other than HTML. You use $scope in your JS and {{}} in HTML which creates a pipe (2-way binding) so that $scope.variable.property has bidirectional binding to {{variable.property }} in HTML.
$scope.includeForm.email === {{ includeForm.email }} === ng-model="includeForm.email" === ng-bind="includeForm.email"
if you set anyone of those all are set so if you set $scope it will show up in HTML and obviously as user input gets captured it is already in $scope ... all connected
when attempting to get the value from HTML back into JS you would need create and set a $scope i.e so if you create $scope.dataModel.dataProperty and use that in ng-model=dataModel.dataProperty (example) you again have two way binding ... you don't need to do anything as angular is taking care of the data pipeline. So if you want to extract the value to var, which is probably a waste as the $scope is already set as soon as the user checks the box
var formField = $scope.dataModel.dataProperty;
// but like I said no need as $scope.dataModel.dataProperty; is your var
In JS if you want to use a dynamic property as an object property key you would place the dynamic value in [] e.g.
$scope.variable[dynamicProperty].method;
// you can set a static property as a key with dot notation i.e.
$scope.variable.staticProperty = val;
Hope that helps
This is my first time using AngularJS, and the form validation is making me question my sanity. You would think this would be the easy part, but no matter how many ways I've tried Googling, the only thing that works is if I set a flag inside my controller's submit if the form is invalid to set the error class. I've looked at similar problems here, but none of them helped, so please do not simply dismiss this as a potential duplicate. Everything else has been a fail.
In the example mark up below I have reduced my form down to just one element. Here is what I have observed:
Using only $error.required does work. The ng-class { 'has-error' :registerForm.firstName.$error.required} does outline the text box with the bootstrap has-ertror class, but this is on form load, which I do not want.
The <p> element with the error message will exhibit the same behavior, so I know that the message exists and is not malfored. It will also display if I only use $error.required. But as soon as I add && registerForm.$submitted ( or $isdirty or !notpristine ) the message will not display on form submit. There are no errors (have developers tools open in chrome) and will post to the web API with no problem and return ok 200 or 400 if I send bad params.
I can write validation code inside my controller, checking if the field has a value and setting a flag on $scope such as $scope.firstNameIsRequired and that will work fine setting ng-show="$scope.firstNameIsRequired", but that will remove testability.
So the problem definitely has to be with how I am adding this in the markup. But after a weekend spent googling I am at my wits end. The only other thing different is that I am using a span on a click element to submit the form instead of an input = submit, but the registerForm.$valid function is setting the correct value. Do I somehow need to trigger the form validation in that ng-click directive?
I am using angular.js v 1.4.8.
I do have angular ui which has it's own validate, but that shouldn't interfere with the basic validation.
Here is the simplified markup:
<form name="registerForm" class="form-group form-group-sm"
ng-controller="userAccountController" novalidate>
<div class="form-group"
ng-class="{ 'has-error' : registerForm.firstName.$error.required }">
<div><label>First Name</label> </div>
<input type="text" class="form-control" id="firstName" name="firstName" value=""
ng-model="firstName" placeholder="First Name" maxlength="100" required=""/>
<p ng-show="registerForm.firstName.$error.required && registerForm.$submitted"
class="alert alert-danger">First Name is required</p>
</div>
<div>
<span class="btn btn-default"
ng-click="submit(registerForm.$valid)">Register</span>
</div>
My controller code is
angular.module( "Application" ).controller( "userAccountController", [
"$scope", "userAccountService", function ( $scope, userAccountService)
{
$scope.hasErrors = false;
$scope.errorMessages = "";
$scope.emailExists = true;
$scope.clearErrors = function (){
$scope.hasErrors = false;
}
$scope.onSuccess = function ( response ) {
alert( "succeeded" );
}
$scope.submit = function (isValid) {
if ($scope.registerForm.$invalid)
return;
alert("isvalid");
$scope.clearErrors();
var userProfile = $scope.createUser();
userAccountService.registerUser(userProfile, $scope.onSuccess, $scope.onError);
}
$scope.createUser = function () {
return {
FirstName: $scope.firstName, LastName: $scope.lastName, Email: $scope.email,
Password: $scope.password, SendAlerts: $scope.sendAlerts
};
};
}
]);
Any help will be appreciated. I probably just need a second set of eyes here because I have been dealing with this on and off since late Friday.
in angular you want use the element.$valid to check wheter an model is valid or not - and you use element.$error.{type} to check for a specific validation error.
Keep in mind that the form.$submitted will only be set if the form is actually submitted - and if it has validationerrors it will not be submitted (and thus that flag is still false)
If you want to show errors only on submit you could use a button with type="submit" and bind to ng-click event - and use that to set a flag that the form has been validated. And handling the submit if the form is valid.
A short example with 2 textboxes, having required and minlength validation:
angular.module("myApp", [])
.controller("myFormController", function($scope) {
$scope.isValidated = false;
$scope.submit = function(myForm) {
$scope.isValidated = true;
if(myForm.$valid) {
console.log("SUCCESS!!");
}
};
});
.form-group {
margin: 10px;
padding: 10px;
}
.form-group.has-error {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<div ng-app="myApp" ng-controller="myFormController">
<form name="myForm">
<div class="form-group" ng-class="{'has-error': myForm.name.$invalid && isValidated}">
<span>Name:</span>
<input type="text" name="name" minlength="5" ng-model="name" required />
<span ng-if="myForm.name.$error.required && isValidated">Name is required</span>
<span ng-if="myForm.name.$error.minlength && isValidated">Length must be atleast 5 characters</span>
</div>
<div class="form-group" ng-class="{'has-error': myForm.email.$invalid && isValidated}">
<span>Email:</span>
<input type="text" name="email" minlength="5" ng-model="email" required />
<span ng-if="myForm.email.$error.required && isValidated">Email is required</span>
<span ng-if="myForm.email.$error.minlength && isValidated">Length must be atleast 5 characters</span>
</div>
<button type="submit" ng-click="submit(myForm)">Submit</button>
</form>
</div>
I am new to AngularJS and trying to design a page which will have two text fields and two radio buttons.
First text field is for current address, followed by radio buttons(one for Yes and second for No), and last component would be permanent address text field. First, user will enter the value in current address text field, after that if user selects yes radio button then it should copy the data from current address to permanent address text field, if user selects No then it should do nothing. Below is the sample code I have written:
*<input type="text" name="cAddress" ng-model="cAddress" required/>
<input type="radio" name="opt" ng-click="copyAddress(true)" />
<input type="radio" name="opt" ng-click="copyAddress(false)" />
<input type="text" name="pAddress" ng-model="pAddress" required/>*
Below is the script code inside controller:
$scope.copyAddress = function(flag) {
if(flag) {
$scope.pAddress = $scope.cAddress;
}
};
when I tried to print $scope.cAddress and $scope.pAddress values in console then it displayed undefined. Even $scope does not have cAddress and pAddress.
Therefore, the main problem is that I am not getting element data inside AngularJS controller
Please find plunker url:
http://plnkr.co/edit/Ub2VEn01HxwDpnCg4tLi?p=preview
Click on Next to navigate to Second tab, there you will find the yes and no radio button to copy the data.
I have minized the code, please look into it. To understand the flow, you can read the README file.
http://plnkr.co/edit/TzJsZIRxAyTuFdCXLFFV?p=preview
Try using another scope object.
That is, create a scope object and add property to it for each input like,
$scope.myObject = {}; // Empty scope variable
$scope.myObject.cAddress = ""; // initialize your model for the input.
And now you should use this variable for your input.
<input type="text" name="cAddress" ng-model="myObject.cAddress" required/>
Try this. It may help you.
Html code:
<body ng-controller='Maincontroller'>
<input type="text" name="cAddress" ng-model="cAddress" />
<input type="radio" name="opt" ng-click="copyAddress(true)" />
<input type="radio" name="opt" ng-click="copyAddress(false)" />
<input type="text" name="pAddress" ng-model="pAddress" />
</body>
Controller code:
var app = angular.module('main', []);
app.controller('Maincontroller', ["$scope",
function($scope) {
$scope.copyAddress = function(flag) {
if (flag) {
$scope.address1 = $scope.address;
} else {
$scope.address1 = "";
}
};
}
]);