angular FormController validation - angularjs

I have this html form:
<div class="modal-body">
<form name="addAdminForm">
<div class="form-group addPopupLabel">
<div class="container-fluid-full" id="email3">
<input placeholder="Email" type="text" ng-model="model.email" required />
</div>
<div class="container-fluid-full">
<input placeholder="Password (at last 6 characters)" type="password" ng-model="model.password1" id="pw1" name="pw1" required />
</div>
<div class="container-fluid-full">
<input placeholder="Confirm password" type="password" ng-model="model.password2" id="pw2" name="pw2" required password-compare="pw1" />
</div>
<div class="container-fluid-full">
<label>Admin</label>
<input type="radio" class="form-control" name="role" ng-model="model.role" ng-value="userRoles.admin">
</div>
<div class="container-fluid-full">
<label>CS</label>
<input type="radio" class="form-control" name="role" ng-model="model.role" ng-value="userRoles.cs">
</div>
<div>
<span class="errormessage" style="color:red">{{errormessage}}</span>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-disabled="addAdminForm.$invalid" ng-click="createForm.$invalid || ok()">Submit</button>
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
</div>
The problem: button stay on disable mode while one of the fields is on focus.
How can i solve it by FormController?

The addAdminForm is scoped within the form. So one option is to move the buttons within the form, or move the form element so that it wraps the buttons. I would prefer this since it is dead simple and most times doable.
If it is not possible for some reason, you can make a directive to export the $invalid flag of a form to a variable of the outer scope. A simple implementation would be:
app.directive('bindValidity', ['$parse', function($parse) {
return {
restrict: 'A',
scope: false,
controller: ['$scope', '$attrs', function($scope, $attrs) {
var assign = $parse($attrs.bindValidity).assign;
if (!angular.isFunction(assign)) {
throw new Error('the expression of bindValidity is not settable: ' + $attrs.bindValidity);
}
this.setFormController = function(formCtrl) {
if (!formCtrl) {
throw new Error('bindValidity requires one of <form> or ng-form');
}
$scope.$watch(
function () {
return formCtrl.$invalid;
},
function (newval) {
assign($scope, newval);
}
);
};
}],
require: ['?form', '?ngForm', 'bindValidity'],
link: function (scope, elem, attrs, ctrls) {
var formCtrl, bindValidity;
formCtrl = ctrls[0] || ctrls[1];
bindValidity = ctrls[2];
bindValidity.setFormController(formCtrl);
}
};
}]);
Use it as:
<div class="modal-body">
<form name="addAdminForm" bind-validity="some.variable">
...
</form>
<div class="modal-footer">
<button ... ng-disabled="some.variable" ng-click="some.variable || ok()">Submit</button>

Related

external template (templateURL) in Angular directive is not working

I'm trying to create an accordion on button click using AngularJS directive. I have external template for creating accordion. But I couldn't get it working. Here is the code:
Directive:
(function() {
'use strict';
angular.module('accountApp')
.directive('addSubsite', addSubsite);
function addSubsite ($compile, $templateRequest){
var ddo = {
restrict: 'A',
link: function(scope, element) {
element.bind("click", function(e){
$templateRequest("addSubsiteTemplate.html").then(function(html){
var template = angular.element(html);
$element.append(template);
$compile(template)(scope);
$element.find(".add-subsites").append(template);
});
});
}
};
return ddo;
}
})();
index.html
<button add-subsite type="button" class="btn btn-primary pull-right margin10-b"id="aid-addSubSitebtn">Add Sub-Site</button>
<accordion>
<accordion-group>
<div class="accordion-heading header">
<a class="accordion-toggle" id="primary__site__address" data-toggle="collapse" href="#primary__site">
<h4><span class="pull-left"><i class="icon-minus"></i></span>Business Name (Primary Site)</h4></a>
</div>
<div class="form-group">
<label for="exampleInputName2">Name</label>
<input type="text" class="form-control" id="exampleInputName2" placeholder="Jane Doe">
</div>
<div class="form-group">
<label for="exampleInputEmail2">Email</label>
<input type="email" class="form-control" id="exampleInputEmail2" placeholder="jane.doe#example.com">
</div>
<button type="submit" class="btn btn-default">Send invitation</button>
</accordion-group>
</accordion>
Template.html
<accordion>
<accordion-group>
<div class="accordion-heading header">
<a class="accordion-toggle"data-toggle="collapse" href="#subsite__site">
<h4><span class="pull-left"><i class="icon-minus"></i></span>Business Name (SubSite)</h4></a>
</div>
<div class="form-group">
<label for="exampleInputName2">Name</label>
<input type="text" class="form-control" id="exampleInputName2" placeholder="Jane Doe">
</div>
<div class="form-group">
<label for="exampleInputEmail2">Email</label>
<input type="email" class="form-control" id="exampleInputEmail2" placeholder="jane.doe#example.com">
</div>
<button type="submit" class="btn btn-default">Send invitation</button>
</accordion-group>
</accordion>
I changed my approach Here is the sample https://jsfiddle.net/2u7aLg5c/
angular.module('testApp',[])
.controller('TestController', function(){
const vm = this;
vm.inputs=[{}];
vm.myInput = [];
vm.add = function(){
vm.inputs.push({})
}
})

Angular validation directive not working properly

I am using custom angular directive for showing validation. Directive code is as below
angularFormsApp.directive('showErrors',['$timeout', function ($timeout) {
return {
restrict: 'A',
require: '^form',
link: function (scope, el, attrs, formCtrl) {
// find the text box element, which has the 'name' attribute
var inputEl = el[0].querySelector("[name]");
// convert the native text box element to an angular element
var inputNgEl = angular.element(inputEl);
// get the name on the text box so we know the property to check
// on the form controller
var inputName = inputNgEl.attr('name');
var helpText = angular.element(el[0].querySelector(".help-block"));
// only apply the has-error class after the user leaves the text box
inputNgEl.bind('blur', function () {
el.toggleClass('has-error', formCtrl[inputName].$invalid);
helpText.toggleClass('hide', formCtrl[inputName].$valid);
});
scope.$on('show-errors-event', function () {
el.toggleClass('has-error', formCtrl[inputName].$invalid);
});
scope.$on('hide-errors-event', function () {
$timeout(function () {
el.removeClass('has-error');
}, 0, false);
});
}
}
}]);
and Html is as below
<div class="container" id="login-form">
<img src="assets/img/logo-big.png">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="panel panel-default">
<div class="panel-heading">
<h2>Login Form</h2>
</div>
<div class="panel-body">
<form name="loginForm" class="form-horizontal" novalidate>
<div class="form-group mb-md" show-errors>
<div class="col-xs-12">
<div class="input-group">
<span class="input-group-addon">
<i class="ti ti-user"></i>
</span>
<input type="text" class="form-control" placeholder="Username" autocomplete="Off" ng-required="true" name="username" autofocus ng-model="loginUser.username">
</div>
<span class="help-block" ng-if="loginForm.username.$error.required">Username is required</span>
</div>
</div>
<div class="form-group mb-md" show-errors>
<div class="col-xs-12" >
<div class="input-group">
<span class="input-group-addon">
<i class="ti ti-key"></i>
</span>
<input type="password" class="form-control" placeholder="Password"
name="password"
ng-model="loginUser.password" autocomplete="Off"
ng-required="true">
</div>
<span class="help-block" ng-if="loginForm.password.$error.required">Password is required</span>
</div>
</div>
<div class="form-group mb-n">
<div class="col-xs-12">
Forgot password?
<div class="checkbox-inline icheck pull-right p-n">
<label for="">
<input type="checkbox"></input>
Remember me
</label>
</div>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<div class="clearfix">
Register
Login
</div>
</div>
</div>
</div>
</div>
</div>
Controller code :
var loginController = function ($scope, $window, $routeParams, $uibModal, $location, $filter, $rootScope, DataService, SharedProperties) {
$rootScope.bodylayout = 'focused-form animated-content';
$scope.loginUser = {
username: "",
password:""
}
$scope.load = function () {
//getAppointmentInfo();
};
$scope.SubmitLoginForm = function () {
$scope.$broadcast('show-errors-event');
if ($scope.loginForm.$invalid)
return;
}
}
angularFormsApp.controller("loginController", ["$scope", "$window", "$routeParams", "$uibModal", "$location", "$filter", "$rootScope", "DataService", "SharedProperties", loginController]);
Now When I open form below input control validation span is displaying by default . When I click on Login button then its showing in red and working fine.
problem is it shouldn't show by default when Page is opend.. Please see image below
Instead of this
loginForm.password.$error.required
try this
(loginForm.$submitted || loginForm.username.$dirty) && loginForm.password.$error.required
Take a look at the ng-messages directive. Its fairly elegant. Example:
<form name="myForm">
<input type="text" ng-model="field" name="myField" required minlength="5" />
<div ng-messages="myForm.myField.$error">
<div ng-message="required">You did not enter a field</div>
<div ng-message="minlength">The value entered is too short</div>
</div>
</form>
You can then combine it with any form validation. Just place the error messages from the validators onto the elements $error object and they are automatically rendered in your UI.
I ended up here as part of my search for an issue. In my case I was using a directive with a changing minimum value like this:
ngOnChanges(changes: SimpleChanges) {
if (changes.minDate && this.control) {
this.control.updateValueAndValidity({ onlySelf: true });
}
}
This means that the form will not be updated, I removed onlySelf and it worked correctly.
this.control.updateValueAndValidity();
Just leaving this as a breadcrumb in case someone else does something similar.

ng-model not updating inside Modal

ng-model which i am assigning is controller can be seen inside modal.But when i am updating the data inside the modal,the $scope variable is not updating.
Also dropdown is not working whose value i have defined in my controller.
Do i need to make changes in directive.
<div ng-controller="MainCtrl" class="container">
<h1>Modal example</h1>
<button ng-click="toggleModal()" class="btn btn-default">Open modal</button>
<modal title="Login form" visible="showModal">
<div>
<select ng-model="client" ng-change="changeClient()" ng-options="item in clientList">
<label for="email">Email address</label>
<input type="text" ng-model="email" id="email" placeholder="Enter email" />
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" placeholder="Password" />
</div>
<button type="submit" ng-click="buttonClicked()" class="btn btn-default">Submit</button>
</modal>
</div>
CONTROLLER CODE
var mymodal = angular.module('mymodal', []);
mymodal.controller('MainCtrl', function ($scope) {
$scope.email="hello#abc.com";
$scope.showModal = false;
$scope.toggleModal = function(){
$scope.showModal = !$scope.showModal;
};
$scope.buttonClicked=function(){
alert("hello1");
alert($scope.email);
alert($scope.client);
}
$scope.clientList=["300","600","900"]
$scope.client=$scope.clientList[0];
$scope.changeClient = function() {
selectedValue=$scope.client;
alert(selectedValue);
};
});
mymodal.directive('modal', function () {
return {
template: '<div class="modal fade">' +
'<div class="modal-dialog">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
'<h4 class="modal-title">{{ title }}</h4>' +
'</div>' +
'<div class="modal-body" ng-transclude></div>' +
'</div>' +
'</div>' +
'</div>',
restrict: 'E',
transclude: true,
replace:true,
scope:true,
link: function postLink(scope, element, attrs) {
scope.title = attrs.title;
scope.$watch(attrs.visible, function(value){
if(value == true)
$(element).modal('show');
else
$(element).modal('hide');
});
$(element).on('shown.bs.modal', function(){
scope.$apply(function(){
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.modal', function(){
scope.$apply(function(){
scope.$parent[attrs.visible] = false;
});
});
}
};
});
Have a Look-JsFiddle Link
you should use:
$parent.email
<input type="text" ng-model="$parent.email" id="email" placeholder="Enter email" />
fiddle
As huan feng said, you can use '$parent' because directive has it's own isolated scope. For your 'select' the simplest solution is to use something like that:
<select ng-model="$parent.client" ng-change="changeClient()" ng-options="item for item in clientList">
But, it could be better to use your model in a little bit different way. Create your 'clientInfo' object with email and clien as properties.
JS:
.controller('MainCtrl', function ($scope) {
$scope.clientInfo = {};
$scope.clientInfo.email="hello#abc.com";
$scope.showModal = false;
$scope.toggleModal = function(){
$scope.showModal = !$scope.showModal;
};
$scope.buttonClicked=function(){
alert("hello1");
alert($scope.clientInfo.email);
alert($scope.clientInfo.client);
}
$scope.clientList=["300","600","900"]
$scope.clientInfo.client = $scope.clientList[0];
$scope.changeClient = function() {
selectedValue=$scope.clientInfo.client;
alert(selectedValue);
};
});
And HTML:
<div ng-controller="MainCtrl" class="container">
<h1>Modal example</h1>
<button ng-click="toggleModal()" class="btn btn-default">Open modal</button>
<modal title="Login form" visible="showModal">
<div>
<select ng-model="clientInfo.client" ng-change="changeClient()" ng-options="item for item in clientList">
<label for="email">Email address</label>
<input type="text" ng-model="clientInfo.email" id="email" placeholder="Enter email" />
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" placeholder="Password" />
</div>
<button type="submit" ng-click="buttonClicked()" class="btn btn-default">Submit</button>
</modal>
</div>

custom directive is not getting called in angular js

I have a simple custom directive with a http post call to a url. When the submit button is clicked it supposed to call the url as custom directive attribute is placed inside the tag.
I checked in chrome console that its not getting called. I am not sure where I went wrong.
Code:
<!DOCTYPE html>
<html ng-app="myApp" >
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script>
var app = angular.module('myApp',[]);
app.directive('sendMail', function ($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
$http.post('MailSenderServlet.do').success(function (data) {
});
}
};
});
</script>
<title>Registration Form</title>
</head>
<body ng-controller="MainCtrl">
<div class="container">
<h2 class="text-muted">Registration form</h2><br/>
<div>
<form name="myForm" action="RegistrationServlet.do" method="POST" novalidate>
<div class="form-group has-feedback">
<label class="control-label">First name:</label> <input type="text" class="form-control input-sm " name="uname" ng-pattern="/^[a-zA-Z]{3,20}/" ng-model="user.uname" placeholder="First Name" required/>
<span style="color:red" ng-show="myForm.uname.$error.pattern">First name cannot be less than 3 letters with no digits</span>
<span style="color:red" class="error" ng-if="myForm.$submitted && myForm.uname.$error.required">Please fill field above<br></span>
<span style="color:red" class="hide-while-in-focus" ng-show="myForm.uname.$error.unique">Username already exist<br/></span>
<span ng-if="myForm.uname.$valid" class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<button class="form-control btn btn-success" type="submit" name="submit" ng-model="submit" send-mail ">Submit</button>
</form>
</div>
</body>
</html>
it should call right after directive loads, place a alert(); inside the link function and remove current items inside the link function and you will see the alert();
DEMO
but if you want to call a function right after the button click, you need ng-click directive and a controller function to execute after the click in directive controller or link function.
<button ng-click="sendData()" class="form-control btn btn-success" type="submit" name="submit" ng-model="submit" send-mail>Submit</button>
ng-click directive added.
app.directive('sendMail', function($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
//alert();
},
controller: function($scope) {
$scope.sendData = function() {
alert('send data here');
}
}
};
});
here is a DEMO
I prefer you shouldn't go for directive if it only contains an ajax call. You can do it just by using ng-click/ng-submit(which is actually meant for forms.) no need of directive here.
You need to correct below certain thing into your code.
We don't need to use ng-model for submit button it doesn't make sense as don't contains any value.
Also you don't need to add action and method attribute on your form, cause anyway you are making from JavaScript code.
While submitting form angular does already provide a directive which is ng-submit.use that would make more sense.
You need to pass data in your post $http.post call.
Markup
<form name="myForm" ng-submit="submit(myForm)" novalidate>
<div class="form-group has-feedback">
<label class="control-label">First name:</label>
<input type="text" class="form-control input-sm " name="uname" ng-pattern="/^[a-zA-Z]{3,20}/" ng-model="user.uname" placeholder="First Name" required/>
<span style="color:red" ng-show="myForm.uname.$error.pattern">First name cannot be less than 3 letters with no digits</span>
<span style="color:red" class="error" ng-if="myForm.$submitted && myForm.uname.$error.required">Please fill field above<br></span>
<span style="color:red" class="hide-while-in-focus" ng-show="myForm.uname.$error.unique">Username already exist<br/></span>
<span ng-if="myForm.uname.$valid" class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<button class="form-control btn btn-success" type="submit" name="submit" send-mail="">Submit</button>
</form>
Controller
$scope.submit = function(form){
if(form.$valid){
$http.post('MailSenderServlet.do', {user: $scope.user})
.success(function (data) {
//
});
}
else
alert("Please validate your form")
}
The issue with your code is simply the controller part you've written
<body ng-controller="MainCtrl">
Either add a controller part, or just remove it, code works fine.
See Demo : http://jsbin.com/hulujarugu/edit?html,console,output
JS:
var app = angular.module('myApp', []);
app.directive('sendMail', function($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
alert(1);
$http.post('MailSenderServlet.do').success(function(data) {});
}
};
});
HTML:
<div class="container">
<h2 class="text-muted">Registration form</h2><br/>
<div>
<form name="myForm" action="RegistrationServlet.do" method="POST" novalidate>
<div class="form-group has-feedback">
<label class="control-label">First name:</label> <input type="text" class="form-control input-sm " name="uname" ng-pattern="/^[a-zA-Z]{3,20}/" ng-model="user.uname" placeholder="First Name" required/>
<span style="color:red" ng-show="myForm.uname.$error.pattern">First name cannot be less than 3 letters with no digits</span>
<span style="color:red" class="error" ng-if="myForm.$submitted && myForm.uname.$error.required">Please fill field above<br></span>
<span style="color:red" class="hide-while-in-focus" ng-show="myForm.uname.$error.unique">Username already exist<br/></span>
<span ng-if="myForm.uname.$valid" class="glyphicon glyphicon-ok form-control-feedback" aria-hidden="true"></span>
</div>
<button class="form-control btn btn-success" type="submit" name="submit" ng-model="submit" send-mail >Submit</button>
</form>
</div>

Chosen dropdown with angular required validation

I am using angular js and the chosen plugin for my dropdowns. I want a validator to show when nothing has been selected in the dropdown. But because chosen replaces the select with some divs and uls, and the select gets hidden, the validation doesn't work. Is there a way I could achieve this with angular? This is my code:
<form class="form-horizontal" role="form" novalidate name="newEmployeeForm">
<div class="form-group">
<label for="username" class="col-sm-3 control-label">User</label>
<div class="col-sm-8">
<select class="form-control" name="user" data-placeholder="Choose a user" ng-model="selectedUser" ng-options="u.fullName for u in users" list="users" chosen required></select>
</div>
<span class="error" data-ng-show="newEmployeeForm.user.$error.required">*</span>
</div>
<div class="form-group">
<label for="email" class="col-sm-3 control-label">Email</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="email" name="email" placeholder="Email" ng-model="employee.email" required>
</div>
<span class="error" data-ng-show="newEmployeeForm.email.$error.required">*</span>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" ng-click="save()" data-ng-disabled="newEmployeeForm.$invalid">Save changes</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</form>
the directive:
app.directive('chosen', function () {
return {
replace: true,
restrict: 'A',
scope: {
list: "="
},
link: function (scope, element, attr) {
scope.$watch('list', function (newVaue, oldValue) {
if (newVaue == oldValue) {
return;
}
element.chosen();
})
}
}
});

Resources