AngularJS: Custom validation based on linked input fields - javascript

Having three input fields
<input type="text" name="foo1" ng-model="data.input1"/>
<ng-messages for="forms.myForm.foo1" role="alert">
<ng-message when="oneRequired"> Please set foo1 (or foo2 or foo3) </ng-message>
<ng-messages>
<input type="text" name="foo2" ng-model="data.input2"/>
<ng-messages for="forms.myForm.foo2" role="alert">
<ng-message when="oneRequired"> Please set foo2 (or foo1 or foo3) </ng-message>
<ng-messages>
<input type="text" name="foo3" ng-model="data.input3"/>
<ng-messages for="forms.myForm.foo3" role="alert">
<ng-message when="oneRequired"> Please set foo3 (or foo1 or foo2) </ng-message>
<ng-messages>
I want to guarantee that at least one input fields value is set. In this case, not only the current validation fields $error should evaluate to 'false' but also all others. All messages should disappear.
My first idea was to use a directive and a unique id to link the fields together:
<input type="text" name="foo1" ng-model="data.input1" one-required="i1_i2_i3_link_identifier/>
Probably I could use a (singleton) service for the registration of the controller and the current values. But I don't have an idea to ensure that all linked controllers (used in the directives) are updated on validation errors.

I highly recommend using the https://github.com/turinggroup/angular-validator directive. It is very flexible and will easily allow to to set your custom validators. I was able to get rid of ng-messages and clean up my html code greatly with this directive.
You can set a custom validator in your controller or service to use throughout your site.
<input type = "text"
name = "firstName"
class = "form-control"
ng-model = "form.firstName"
validator = "myCustomValidator(form.firstName)"
validate-on="dirty"
required></div>
Here is a plunker and code for you: http://plnkr.co/edit/X5XdYYekT4YZH6xVBftz?p=preview As you can see this is very clunky and there is a lot of code. With angular validator you can reduce your code to be inline within your inputs and add a controller function.
<form name="myForm">
<input type="text" name="foo1" ng-model="data.input1" required/>
<div ng-if="myForm.foo1.$error.required && myForm.foo2.$error.required && myForm.foo3.$error.required" class="error">
<ng-messages for="myForm.foo1" role="alert">
<ng-message="required"> Please set foo1 (or foo2 or foo3) </ng-message>
</ng-messages>
</div>
<br/>
<input type="text" name="foo2" ng-model="data.input2" required/>
<div ng-if="myForm.foo1.$error.required && myForm.foo2.$error.required && myForm.foo3.$error.required" class="error">
<ng-messages for="myForm.foo2" role="alert">
<ng-message="required"> Please set foo2 (or foo2 or foo3) </ng-message>
</ng-messages>
</div>
<br/>
<input type="text" name="foo3" ng-model="data.input3" required/>
<div ng-if="myForm.foo1.$error.required && myForm.foo2.$error.required && myForm.foo3.$error.required" class="error">
<ng-messages for="myForm.foo3" role="alert">
<ng-message="required"> Please set foo3 (or foo2 or foo3) </ng-message>
</ng-messages>
</div>
<br/>
</form>

I solved the problem using a central Service holding the values and a callback registry. The callbacks are called all the time, when the input changes (using a watcher):
angular.module('myApp', []);
angular.module('myApp').controller('myFormController', function($scope) {
$scope.data = {
i1: "remove",
i2: "all",
i3: "values"
};
});
angular.module('myApp').factory('oneRequiredService', function() {
var service = {};
var container = {};
var observerCallbacks = {};
var isValid = function(groupId) {
var valid = false;
var modelStates = container[groupId];
angular.forEach(modelStates, function(modelValid) {
valid = valid || (modelValid ? true : false);
});
return valid;
};
var isRegistered = function(groupId) {
return container.hasOwnProperty(groupId);
};
var notifyAll = function(key) {
var valid = isValid(key);
if (isRegistered(key)) {
angular.forEach(observerCallbacks[key], function(callback, index) {
callback(valid);
});
};
};
service.register = function(groupId, scopeId, callback) {
this.updateValue(groupId, scopeId, undefined);
if (callback) {
this.registerCallback(groupId, callback);
}
};
service.registerCallback = function(groupId, callback) {
if (callback) {
observerCallbacks[groupId] = observerCallbacks[groupId] || [];
observerCallbacks[groupId].push(callback);
};
};
service.updateValue = function(groupId, scopeId, value) {
container[groupId] = container[groupId] || {};
container[groupId][scopeId] = value;
notifyAll(groupId);
};
return service;
});
angular.module('myApp').directive('oneRequired', function(oneRequiredService) {
return {
restrict: "A",
require: 'ngModel',
scope: true,
link: function(scope, element, attrs, ctrl) {
var modelAttr = attrs["ngModel"];
var linkIdentifier = attrs["oneRequired"];
var updateCurrentState = function(isValid) {
scope._valid = isValid;
};
scope.$watch(modelAttr, function(newVal, oldVal) {
oneRequiredService.updateValue(linkIdentifier, scope.$id, newVal);
});
scope.$watch('_valid', function(newVal, oldVal) {
ctrl.$setValidity('oneRequired', newVal);
});
oneRequiredService.register(linkIdentifier, scope.$id, updateCurrentState);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script>
<body ng-app="myApp">
<form ng-controller="myFormController" name="forms.myForm">
<label for="i_1">i_1</label>
<input id="i_1" name="i1" type="text" one-required="foo-bar" ng-model="data.i1" />
<span> i1-err-one-required: {{forms.myForm.i1.$error.oneRequired}} </span> <br>
<label for="i_2">i_2</label>
<input id="i_2" name="i2" type="text" one-required="foo-bar" ng-model="data.i2"/>
<span> i2 err-one-required: {{forms.myForm.i2.$error.oneRequired}} </span> <br>
<label for="i_3">i_3</label>
<input id="i_3" name="i3" type="text" one-required="foo-bar" ng-model="data.i3"/>
<span> i3-err-one-required: {{forms.myForm.i3.$error.oneRequired}} </span> <br>
</form>
</body>

Related

knockoutjs using module pattern not working

I am trying to create simple knockout example using module pattern
var login = {}; //login namespace
//Constructor
login.UserData = function () {
var self = this;
self.UserName = ko.observable("");
self.Password = ko.observable("");
};
//View-Model
login.UserVM = function () {
this.userdata = new login.UserData(),
this.apiUrl = 'http://localhost:9090/',
this.authenticate = function () {
var data = JSON.parse(ko.toJSON(this.userdata));
var service = apiUrl + '/api/Cryptography/Encrypt';
DBconnection.fetchdata('POST', service, JSON.stringify(data.Password), response, function () { console.log('Cannot fetch data') }, null, true);
function response(res) {
console.log(res)
}
}
return {
authenticate: this.authenticate
}
}();
$(function () {
ko.applyBindings(login.UserVM); /* Apply the Knockout Bindings */
});
HTML CODE:
<form id="loginform" name="loginForm" method="POST">
<div id="form-root">
<div>
<label class="form-label">User Name:</label>
<input type="text" id="txtFirstName" name="txtFirstName" data-bind="value:login.UserData.UserName" />
</div>
<div>
<label class="form-label">Password:</label>
<input type="text" id="txtLastName" name="txtLastName" data-bind="value:login.UserData.Password" />
</div>
<div>
<input type="button" id="btnSubmit" value="Submit" data-bind="click: authenticate" />
</div>
</div>
</form>
the problem is am not able to get userdata in the viewmodel on click of submit it is returning undefined and the login object holds the changed value of textbox but on click it is returning black values.
please let me know
Also can you let me know how to implement definative module pattern in the same code.
The object you are returning from login.UserVM has only authenticate property and doesn't have userdata or apiUrl properties. So, instead using an IIFE to create an object, set login.UserVM to a constructor function similar to login.UserData. And then use new operator to create the viewModel object. Now the viewModel will have userdata and apiUrl properties (remove the return from the function)
Also, you need to change the HTML bindings to: data-bind="value:userdata.UserName". This looks for the userdata property inside the bound viewModel
var login = {}; //login namespace
//Constructor
login.UserData = function () {
var self = this;
self.UserName = ko.observable("");
self.Password = ko.observable("");
};
//View-Model
login.UserVM = function () {
this.userdata = new login.UserData(),
this.apiUrl = 'http://localhost:9090/',
this.authenticate = function () {
var data = JSON.parse(ko.toJSON(this.userdata));
console.log(data)
//var service = this.apiUrl + '/api/Cryptography/Encrypt';
//DBconnection.fetchdata('POST', service, JSON.stringify(data.Password), response, function () { console.log('Cannot fetch data') }, null, true);
function response(res) {
console.log(res)
}
}
}; // remove the () from here
ko.applyBindings(new login.UserVM()); /* Apply the Knockout Bindings */
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<form id="loginform" name="loginForm" method="POST">
<div id="form-root">
<div>
<label class="form-label">User Name:</label>
<input type="text" id="txtFirstName" name="txtFirstName" data-bind="value:userdata.UserName" />
</div>
<div>
<label class="form-label">Password:</label>
<input type="text" id="txtLastName" name="txtLastName" data-bind="value:userdata.Password" />
</div>
<div>
<input type="button" id="btnSubmit" value="Submit" data-bind="click: authenticate" />
</div>
</div>
</form>

Function treated as string in Angular JS

I have an html form that takes a name and a location and Posts it to a mobile service table.
<form name="userform" ng-submit="addName(user)">
<p>name: <input type="text" id="name" ng-model="user.name" /></p>
<p>location: <input type="text" id="location" ng-model="user.location"/></p>
<button id="btn-add-evangelist">Add to list</button>
</form>
and this is how I retrieve data from the form in Angular
$scope.people = [];
$scope._name = "Default Name";
$scope._location = "Default Location";
$scope.user = {
name: function (theName) {
if (angular.isDefined(theName)) {
$scope._name = theName;
}
return $scope._name;
},
location: function (theLocation) {
if (angular.isDefined(theLocation)) {
$scope._location = theLocation;
}
return $scope._location;
}};
however, when I run the html, the location textbox has the function code instead of the "Default Location" string, and the name textbox is blank instead of "Default Name".
I wonder what can be wrong here. Any help is appreciated.
AngularJS works correct. It basically takes the string representation of the function, and sets it as the value of the textbox.
If you need the evaluated value instead, you need to call the function by putting a parentheses after the function name, like this:
angular.module('myapp', [])
.controller('myctrl', function($scope) {
$scope.people = [];
$scope._name = "Default Name";
$scope._location = "Default Location";
$scope.user = {
name: function(theName) {
if (angular.isDefined(theName)) {
$scope._name = theName;
}
return $scope._name;
}(),
location: function(theLocation) {
if (angular.isDefined(theLocation)) {
$scope._location = theLocation;
}
return $scope._location;
}()
};
});
<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="userform" ng-submit="addName(user)">
<p>name: <input type="text" id="name" ng-model="user.name" /></p>
<p>location: <input type="text" id="location" ng-model="user.location" /></p>
<button id="btn-add-evangelist">Add to list</button>
</form>
</div>
You can set directly the default value to the model like this:
$scope.people = [];
$scope._name = "Default Name";
$scope._location = "Default Location";
$scope.user = { //set default value to the inputs
name:$scope._name,
location:$scope._location
}
If you are using latest version of angular js. Try ng-model-options="{ getterSetter: true }".
Sometimes it's helpful to bind ngModel to a getter/setter function. A
getter/setter is a function that returns a representation of the model
when called with zero arguments, and sets the internal state of a
model when called with an argument. It's sometimes useful to use this
for models that have an internal representation that's different from
what the model exposes to the view.
Best Practice: It's best to keep getters fast because AngularJS is
likely to call them more frequently than other parts of your code. You
use this behavior by adding ng-model-options="{ getterSetter: true }"
to an element that has ng-model attached to it. You can also add
ng-model-options="{ getterSetter: true }" to a , which will
enable this behavior for all s within it. See ngModelOptions
for more.
angular.module('myapp', [])
.controller('myctrl', function($scope) {
$scope.people = [];
$scope._name = "Default Name";
$scope._location = "Default Location";
$scope.user = {
name: function(theName) {
if (angular.isDefined(theName)) {
$scope._name = theName;
}
return $scope._name;
},
location: function(theLocation) {
if (angular.isDefined(theLocation)) {
$scope._location = theLocation;
}
return $scope._location;
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"></script>
<div ng-app="myapp" ng-controller="myctrl">
<form name="userform" ng-submit="addName(user)">
<p>name: <input type="text" id="name" ng-model="user.name" ng-model-options="{ getterSetter: true }"/></p>
<p>location: <input type="text" id="location" ng-model="user.location" ng-model-options="{ getterSetter: true }"/></p>
<button id="btn-add-evangelist">Add to list</button>
</form>
</div>

How to use the Angular jQuery Validate's checkForm() function

EDIT:
I've added a JsFiddle so you can easily troubleshoot instead of having to set up the environment yourself. As you can see, validation is done on the Email field even before the blur event on the input element, which was triggered by the $scope.Email being changed. If you comment out the ng-show="!mainForm.validate()" on the <p> element, you'll see that the issue doesn't take place.
I am using the Angular implementation of jQuery Validate, and I am in need of the ability to check if a form is valid without showing the error messages. The standard solution I've seen online is to use jQuery Validate's checkForm() function, like this:
$('#myform').validate().checkForm()
However, the Angular wrapper I'm using doesn't currently implement the checkForm function. I have been trying to modify the source code to bring it in, and I'm afraid I'm in over my head. The code is small and simple enough that I'll paste it here:
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
//This is the part I've tried adding in.
//It runs, but still shows error messages when executed.
//form.checkForm = function() {
// return validator.checkForm();
//}
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
I want to be able to use it to show or hide a message, like this:
<p class="alert alert-danger" ng-show="!mainForm.checkForm()">Please correct any errors above before saving.</p>
The reason I don't just use !mainForm.validate() is because that causes the error messages to be shown on elements before they are "blurred" away from, which is what I'm trying to avoid. Can anyone help me implement the checkForm() function into this angular directive?
You can add checkForm() function to the plugin as following.
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.checkForm = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.checkForm();
validator.submitted = {};
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
Please find the updated jsFiddle here https://jsfiddle.net/b2k4p3aw/
Reference: Jquery Validation: Call Valid without displaying errors?
If I understand your question correctly, you want to be able to show an error message when the email adress is invalid and you decide you want to show the error message.
You can achieve this by setting the input type to email like this <input type=email>
Angular adds an property to the form $valid so you can check in your controller if the submitted text is valid. So we only have to access this variable in the controller and invert it. (Because we want to show the error when it is not valid)
$scope.onSubmit = function() {
// Decide here if you want to show the error message or not
$scope.mainForm.unvalidSubmit = !$scope.mainForm.$valid
}
I also added a submit button that uses browser validation on submit. This way the onSubmit function won't even get called and the browser will show an error. These methods don't require anything except angularjs.
You can check the updated JSFiddle here
Make sure to open your console to see when the onSubmit function gets called and what value gets send when you press the button.
You can use $touched, which is true as soon as the field is focused then blurred.
<p class="alert alert-danger" ng-show="mainForm.Email.$touched && !mainForm.validate()">Please correct any errors above before saving.</p>
you can achieve onblur event with ng-show="mainForm.Email.$invalid && mainForm.Email.$touched" to <p> tag
by default mainForm.Email.$touched is false, on blur it will change to true
for proper validation change the <input> tag type to email
you can add ng-keydown="mainForm.Email.$touched=false" if you don't want to show error message on editing the input tag
I didn't used angular-validate.js plugin
<div ng-app="PageModule" ng-controller="MainController" class="container"><br />
<form method="post" name="mainForm" ng-submit="OnSubmit(mainForm)" >
<label>Email:
<input type="email" name="Email" ng-keydown="mainForm.Email.$touched=false" ng-model="Email" class="email" />
</label><br />
<p class="alert alert-danger" ng-show="mainForm.Email.$invalid && mainForm.Email.$touched">Please correct any errors above before saving.</p>
<button type="submit">Submit</button>
</form>
</div>
Updated code : JSFiddle
AngularJs Form Validation
More info on Angular validation
Update 2
checkForm will return whether the form is valid or invalid
// added checForm, also adds valid and invalid to angular
form.checkForm = function (){
var valid = validator.form();
angular.forEach(validator.successList, function(value, key) {
scope.$parent[formName][value.name].$setValidity(value.name,true);
});
angular.forEach(validator.errorMap, function(value, key) {
scope.$parent[formName][key].$setValidity(key,false);
});
return valid
}
to hide default messages adding by jQuery validation plugin add below snippet, to $.validator.setDefaults
app.config(function ($validatorProvider) {
$validatorProvider.setDefaults({
errorPlacement: function(error,element) { // to hide default error messages
return true;
}
});
});
here is the modified plugin looks like
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
var formName = validator.currentForm.name;
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
// added checkForm
form.checkForm = function (){
var valid = validator.form();
angular.forEach(validator.successList, function(value, key) {
scope.$parent[formName][value.name].$setValidity(value.name,true);
});
angular.forEach(validator.errorMap, function(value, key) {
scope.$parent[formName][key].$setValidity(key,false);
});
return valid
}
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
controller
app.controller("MainController", function($scope) {
$scope.Email = "";
$scope.url = "";
$scope.isFormInValid = false; // to hide validation messages
$scope.OnSubmit = function(form) {
// here you can determine
$scope.isFormInValid = !$scope.mainForm.checkForm();
return false;
}
})
need to have following on every input tag(example for email)
ng-show="isFormInValid && !mainForm.Email.$invalid "
if the form and email both are invalid the validation message shows up.
JSFiddle
try this code for validation this is the form
<form name="userForm" ng-submit="submitForm(userForm.$valid)" novalidate>
<div class="form-group">
<input type="text" ng-class="{ 'has-error' : userForm.name.$invalid && !userForm.name.$pristine }" ng-model="name" name="name" class="form-control" placeholder="{{ 'regName' | translate }}" required>
<p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">Your name is required.</p>
</div>
<div class="form-group">
<input type="tel" ng-class="{ 'has-error' : userForm.mob.$invalid && !userForm.mob.$pristine }" ng-model="mob" class="form-control" name="mob" ng-maxlength="11" ng-minlength="11" ng-pattern="/^\d+$/" placeholder="{{ 'regPhone' | translate }}" required>
<p ng-show="userForm.mob.$invalid && !userForm.mob.$pristine" class="help-block">Enter a valid number</p>
</div>
<div class="form-group">
<input type="email" ng-model="email" name="email" class="form-control" placeholder="{{ 'regEmail' | translate }}" required>
<p ng-show="userForm.email.$invalid && !userForm.email.$pristine" class="help-block">Enter a valid email.</p>
</div>
<div class="form-group">
<input type="password" ng-model="pass" name="pass" class="form-control" placeholder="{{ 'regPass' | translate }}" minlength="6" maxlength="16" required>
<p ng-show="userForm.pass.$invalid && !userForm.pass.$pristine" class="help-block"> Too short Min:6 Max:16</p>
<input type="password" ng-model="repass" class="form-control" ng-minlength="6" placeholder="{{ 'regConPass' | translate }}" ng-maxlength="16" required>
</div>
<button class="loginbtntwo" type="submit" id="regbtn2" ng-disabled="userForm.$dirty && userForm.$invalid" translate="signUp" ></button>
</form>
You will need to modify the Angular Validate Plugin a bit. Here is a working version of your code in JSFiddle. Note the updated plugin code as well as a pair of modifications to your original code.
Updated plugin code simply adds this to validator.SetDefaults parameter:
errorPlacement: function(error,element) { return true; } // to hide default error message
Then we use a scope variable to hide/show the custom error message:
$scope.OnSubmit = function(form) {
if (form.$dirty) {
if (form.validate()) {
//form submittal code
} else {
$scope.FormInvalid = true;
}
}

JS wont recognize a variable within angular controller object

Im trying to create a simple login verification, however the validation function seizes to function when the validation comparison begins, and the console sais that the variable "userName is not defined" although it clearly is.
Can enyone tell me what am i defining wrong?
the angular controller code:
var app = angular.module("LoginApp", []);
app.controller("LoginController", function ($http) {
this.userName = "";
this.password = "";
this.userNameValid = true;
this.passwordValid = true;
/*submit the form*/
this.submit = function () {
alert("submit");
this.validate();
};
/* make sure user name and password has been inserted*/
this.validate = function () {
alert("validate");
var result = true;
this.userNameValid = true;
this.passwordValid = true;
if (this.userName == "") {
alert("username="+userName);
this.userNameValid = false;
result = false;
}
if (this.password == "") {
this.passwordValid = false;
result = false;
}
alert("validuserNameValid==" + userNameValid + " passwordValid==" + passwordValid);
return result;
};
});
the HTML form:
<body ng-app="LoginApp" ng-controller="LoginController as LoginController">
<form role="form" novalidate name="loginForm" ng-submit="LoginController.submit()">
<div id="loginDetails">
<div class="form-group">
<label for="user"> User Name:</label>
<input type="text" id="user" class="form-control" ng-model="LoginController.userName" required />
<span ng-show="LoginController.userNameValid==false" class="alert-danger">field is requiered</span>
</div>
<div class="form-group">
<label for="password" >Password:</label>
<input type="password" id="password" class="form-control" ng-model="LoginController.password" required />
<span ng-show="LoginController.passwordValid==false" class="alert-danger">field is requiered</span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
{{"entered information:" +"\n"+LoginController.userName+" "+ LoginController.password}}
</div>
</div>
</form>
</body>
the log:
Error: userName is not defined
this.validate#http://localhost:39191/login.js:23:13
this.submit#http://localhost:39191/login.js:11:9
anonymous/fn#https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js line 231 > Function:2:292
b#https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js:126:19
Kc[b]</<.compile/</</e#https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js:274:195
uf/this.$get</m.prototype.$eval#https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js:145:103
uf/this.$get</m.prototype.$apply#https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js:145:335
Kc[b]</<.compile/</<#https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js:274:245
Rf#https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js:37:31
Qf/d#https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js:36:486
Always use this judiciously. I would recommend you to store the reference of this in variable then use it wherever required.
var app = angular.module("LoginApp", []);
app.controller("LoginController", function ($http) {
//Store the reference of this in a variable
var lc = this;
//Use the stored refrence
lc.userName = "";
/* make sure user name and password has been inserted*/
lc.validate = function () {
if (lc.userName == "") {
alert("username="+userName);
lc.userNameValid = false;
result = false;
}
};
});
inside your alert boxes you have not mentioned this.userName try removing the alert boxes or change them.

using $watch in angularjs

I have a form with 2 input fields and requirement is that once user enters valid data into these
fields, I need to pass the input data to the factory function and get the data from server.To achieve this I thought of using $watch function but stuck at how to know if form is valid in $wathc function and then call the factory function to get data from the server.Here is the code.
Any help would be highly appreciated.
//html
<html>
<body ng-app="myModule">
<div ng-controller="myCtrl">
Product Id: <input type="text" ng-model="myModel.id" /><br/>
Product Name: <input type="text" ng-model="myModel.productname" /><br/>
</div>
</body>
</html>
//js
var myModule = angular.module('myModule',[]);
myModule.controller('myCtrl',['$scope', function($scope){
$scope.myModel = {};
var getdata = function(newVal, oldVal) {
};
$scope.$watch('myModel.id', getdata)
$scope.$watch('myModel.productname', getdata)
}]);
Wouldn't you just watch myModel, since the same function is called in both cases?
You could do this with ng-change just as easily.
<html>
<body ng-app="myModule">
<form name="productForm" ng-controller="myCtrl">
<div>
Product Id: <input type="text" name="idModel" ng-model="myModel.id" ng-change="validateID()" /><br/>
Product Name: <input type="text" ng-model="myModel.productname" ng-change="validateProduct()" /><br/>
</div>
</form>
</body>
And your JS would look like this:
var myModule = angular.module('myModule',[]);
myModule.controller('myCtrl',['$scope', 'myFactory',
function($scope, myFactory){
$scope.myModel = {};
$scope.validateID = function(){
//things that validate the data go here
if(your data is valid){
myFactory.get(yourParams).then(function(data){
//whatever you need to do with the data goes here
});
}
};
$scope.validateProduct = function(){
//things that validate the data go here
if(your data is valid){
myFactory.get(yourParams).then(function(data){
//whatever you need to do with the data goes here
});
}
};
}
]);
Using ng-change saves you from having to add a $watch to your scope (they are expensive) and will fire when the user leaves the input box. If you need to catch each keystroke, I would recommend that you use UI-Keypress and run the same functions.
To know if form is valid you have to add a form tag and inside your controller check $valid, on your example the form is always valid becaus you do not have any required field.
See the below example on codepen
The HTML
<div ng-app="myModule">
<div ng-controller="myCtrl">
<form name="myform" novalidate>
Product Id:
<input type="text" ng-model="myModel.id" />
<br/>
Product Name:
<input type="text" ng-model="myModel.productname" />
<br/>
</form>
<br/>
<div>{{result}}</div>
<div>Form is valid: {{myform.$valid}}</div>
</div>
</div>
The JS
var myModule = angular.module('myModule', []);
myModule.controller('myCtrl', ['$scope', function ($scope) {
$scope.myModel = {};
$scope.result = "(null)";
var getdata = function (newVal, oldVal) {
var valid = null;
if ($scope.myform.$valid) {
valid = "is valid";
} else {
valid = "is INVALID";
}
$scope.result = "Changed value " + newVal + " form " + valid;
};
$scope.$watch('myModel.id', getdata);
$scope.$watch('myModel.productname', getdata);
}]);

Categories