Angular - Dependent Field Validation - javascript

I got a problem. I'm trying to create a validation directive for my form. My validation process is a bit complex. I got 4 selects (dropdowns). 2 dropdowns for a first team (user and deputy) and the same for a second team.
My validation directive needs to do the following:
User first team selected but not a deputy first team (require deputy first team)
Deputy first team selected but not a user first team (require user first team)
User second team selected but not a deputy second team (require deputy second team)
Deputy second team selected but not a user second team (require user second team)
No user nor deputy for first or second team selected (require at least one user or deputy)
My html looks like this:
<div class="row" ng-form="reportForm" ng-model="report" require-users>
<!-- User First Team -->
<div class="col-sm-3 col-xs-6">
<div class="form-group">
<label>User First Team</label>
<!-- Dropdown User First Team -->
<select ng-form="reportForm.userFirst"
ng-model="report.userFirst"
ng-options="user.Name for user in users track by user.Id"
class="form-control">
<option></option>
</select>
<!-- Error Messages-->
<div ng-messages="reportForm.$error" style="color:maroon; margin-top: 4px;" role="alert">
<!-- Message required -->
<div ng-message="requireUserFirst">
<small>A User for the first team is required.</small>
</div>
</div>
</div>
</div>
<!-- Deputy First Team -->
<div class="col-sm-3 col-xs-6">
<div class="form-group">
<label>Deputy First Team</label>
<!-- Dropdown Deputy First Team -->
<select ng-form="reportForm.deputyFirst"
ng-model="report.deputyFirst"
ng-options="user.Name for user in users track by user.Id"
class="form-control">
<option></option>
</select>
<!-- Error messages -->
<div ng-messages="reportForm.$error" style="color:maroon; margin-top: 4px;" role="alert">
<!-- Message required -->
<div ng-message="requireDeputyFirst">
<small>A Deputy for the first team is required.</small>
</div>
</div>
</div>
</div>
<!-- User Second Team -->
<div class="col-sm-3 col-xs-6">
<div class="form-group">
<label>User Second Team</label>
<!-- Dropdown User Second Team -->
<select ng-form="reportForm.userSecond"
ng-model="report.userSecond"
ng-options="user.Name for user in users track by user.Id"
class="form-control">
<option></option>
</select>
<!-- Error messages -->
<div ng-messages="reportForm.$error" style="color:maroon; margin-top: 4px;" role="alert">
<!-- Message required -->
<div ng-message="requireUserSecond">
<small>A User for the second team is required.</small>
</div>
</div>
</div>
</div>
<!-- Deputy Second Team -->
<div class="col-sm-3 col-xs-6">
<div class="form-group">
<label>Deputy Second Team</label>
<!-- Dropdown Deputy Second Team -->
<select ng-form="reportForm.deputySecond"
ng-model="report.deputySecond"
ng-options="user.Name for user in users track by user.Id"
class="form-control">
<option></option>
</select>
<!-- Error messages -->
<div ng-messages="reportForm.$error" style="color:maroon; margin-top: 4px;" role="alert">
<!-- Message required -->
<div ng-message="requireDeputySecond">
<small>A Deputy for the second team is required.</small>
</div>
</div>
</div>
</div>
<!-- Error messages -->
<div ng-messages="reportForm.$error" style="color:maroon; margin-top: 4px;" role="alert" class="col-xs-12">
<!-- Message missing user and deputy -->
<div ng-message="requireAll">
<small><strong>At least one user and deputy is needed.</strong></small>
</div>
</div>
</div>
And my directive is here:
app.directive('requireUsers', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attr, ngModel) {
scope.$watch(function () {
return ngModel.$modelValue;
}, function (model, oldModel) {
if (model != oldModel) {
if (model.userFirst == null && model.deputyFirst == null && model.userSecond == null && model.deputySecond == null) {
ngModel.$setValidity('requireAll', false);
} else {
ngModel.$setValidity('requireAll', true);
}
if ((model.userFirst == undefined || model.userFirst == null) && model.deputyFirst != null) {
ngModel.$setValidity('requireUserFirst', false);
} else {
ngModel.$setValidity('requireUserFirst', true);
}
if ((model.deputyFirst == undefined || model.deputyFirst == null) && model.userFirst != null) {
ngModel.$setValidity('requireDeputyFirst', false);
} else {
ngModel.$setValidity('requireDeputyFirst', true);
}
if ((model.userSecond == undefined || model.userSecond == null) && model.deputySecond != null) {
ngModel.$setValidity('requireUserSecond', true);
} else {
ngModel.$setValidity('requireUserSecond', true);
}
if ((model.deputySecond == undefined || model.deputySecond == null) && model.userSecond != null) {
ngModel.$setValidity('requireDeputySecond', false);
} else {
ngModel.$setValidity('requireDeputySecond', true);
}
}
});
}
};
});
The problem is that the watcher doesn't work only when the directive gets initialized. So when I change a value the validation process won't get started.
UPDATE ReportController:
angular.module('ReportTool')
.controller('ReportController', ['$scope', 'Report', 'User', function ($scope, Report, User) {
var _this = this;
// Load all Teammembers (API Call in Service)
User.query().then(function (success) {
_this.users= success.data;
}, function (error) {
console.log('Users could not be loaded.');
});
// Save report
this.save = function () {
if (_this.report != null) {
// create report
Report.post(_this.report).then(function (success) {
console.log('Report created.');
}, function (error) {
console.log('Report could not be created.');
} else {
console.log('Report is null.');
}
};
}]);

In this case, you need to write a directive for each check, like the requireUsers.
I recommend using directive use-form-error.
With it easy to create custom checks.
Live example on jsfiddle.
angular.module('ExampleApp', ['use', 'ngMessages'])
.controller('ExampleController', function($scope) {
});
.errors {
color: maroon
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdn.rawgit.com/Stepan-Kasyanenko/use-form-error/master/src/use-form-error.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular-messages.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<form name="myForm">
<label>User first:</label>
<input type="text" ng-model="userFirst" name="userFirst" use-form-error="requireUserFirst" use-error-expression="!userFirst && deputyFirst" />
<br>
<label>Deputy first:</label>
<input type="text" ng-model="deputyFirst" name="deputyFirst" use-form-error="requireDeputyFirst" use-error-expression="userFirst && !deputyFirst"/>
<br>
<hr>
<label>User second:</label>
<input type="text" ng-model="userSecond" name="userSecond" />
<br>
<label>Deputy second:</label>
<input type="text" ng-model="deputySecond" name="deputySecond" />
<br>
<div use-form-error="requireAll" use-error-expression="!userFirst && !deputyFirst && !userSecond && !deputySecond" use-error-input="myForm"> </div>
<div ng-messages="myForm.$error" class="errors">
<div ng-message="requireAll">At least one user and deputy is needed.</div>
</div>
<div ng-messages="myForm.userFirst.$error" class="errors">
<div ng-message="requireUserFirst">A User for the first team is required.</div>
</div>
<div ng-messages="myForm.deputyFirst.$error" class="errors">
<div ng-message="requireDeputyFirst">A Deputy for the first team is required.</div>
</div>
</form>
</div>
</div>

You can simple pass your variable into your directive. And then check it.
Live examplee on jsfiddle.
angular.module('ExampleApp', ['ngMessages'])
.controller('ExampleController', function($scope) {
})
.directive('requireUsers', function() {
return {
restrict: 'A',
require: 'form',
scope: {
userFirst: "=",
deputyFirst: "=",
userSecond: "=",
deputySecond: "=",
},
link: function(scope, elem, attr, ngModel) {
function changeValue(model, oldModel) {
if (!scope.userFirst && !scope.deputyFirst && !scope.userSecond && !scope.deputySecond) {
ngModel.$setValidity('requireAll', false);
} else {
ngModel.$setValidity('requireAll', true);
}
if (!scope.userFirst && scope.deputyFirst) {
ngModel.$setValidity('requireUserFirst', false);
} else {
ngModel.$setValidity('requireUserFirst', true);
}
if (!scope.deputyFirst && scope.userFirst) {
ngModel.$setValidity('requireDeputyFirst', false);
} else {
ngModel.$setValidity('requireDeputyFirst', true);
}
if (!scope.userSecond && scope.deputySecond) {
ngModel.$setValidity('requireUserSecond', false);
} else {
ngModel.$setValidity('requireUserSecond', true);
}
if (!scope.deputySecond && scope.userSecond) {
ngModel.$setValidity('requireDeputySecond', false);
} else {
ngModel.$setValidity('requireDeputySecond', true);
}
}
scope.$watch('userFirst', changeValue);
scope.$watch('deputyFirst', changeValue);
scope.$watch('userSecond', changeValue);
scope.$watch('deputySecond', changeValue);
}
};
});;
.errors {
color: maroon
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular-messages.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<form name="myForm" require-users user-first="userFirst" deputy-first="deputyFirst" user-second="userSecond" deputy-second="deputySecond">
<label>User first:</label>
<input type="text" ng-model="userFirst" name="userFirst" />
<br>
<label>Deputy first:</label>
<input type="text" ng-model="deputyFirst" name="deputyFirst" />
<br>
<hr>
<label>User second:</label>
<input type="text" ng-model="userSecond" name="userSecond" />
<br>
<label>Deputy second:</label>
<input type="text" ng-model="deputySecond" name="deputySecond" />
<br>
<div ng-messages="myForm.$error" class="errors">
<div ng-message="requireAll">At least one user and deputy is needed.</div>
<div ng-message="requireUserFirst">A User for the first team is required.</div>
<div ng-message="requireDeputyFirst">A Deputy for the first team is required.</div>
<div ng-message="requireUserSecond">A User for the second team is required.</div>
<div ng-message="requireDeputySecond">A Deputy for the second team is required.</div>
</div>
</form>
</div>
</div>

Related

Dynamically display form data using AngularJS

I would like to dynamically display Person and Address data using label and input value in Summary Section. As the user edits the form fields, a list items with label + value should display in the summary tables. If value has been removed in the form, that associated label and value should be removed from the Summary Section.
I have added client side validation for each input element. I tried to solve this and couldn't figure out what is best way to do it. Any help would be appreciated.
Example:
// the main (app) module
var myApp = angular.module("myApp", []);
// add a controller
myApp.controller("myCtrl", function($scope) {
$scope.vm = {
caller: {
person: {
firstName: '',
lastName: '',
phoneOne: '',
email: ''
},
address: {
lineOne: '',
lineTwo: ''
}
}
};
$scope.save = function() {
console.log($scope.vm);
}
});
// add a directive
myApp.directive('showErrors', function($timeout, $compile) {
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
var inputName = inputNgEl.attr('name');
// only apply the has-error class after the user leaves the text box
var blurred = false;
inputNgEl.bind('blur', function() {
blurred = true;
el.toggleClass('has-error', formCtrl[inputName].$invalid);
});
scope.$watch(function(scope) {
return formCtrl[inputName].$invalid;
}, function(invalid, scope) {
// we only want to toggle the has-error class after the blur
// event or if the control becomes valid
if (!blurred && invalid) {
return
}
el.toggleClass('has-error', invalid);
});
scope.$on('show-errors-check-validity', function() {
el.toggleClass('has-error', formCtrl[inputName].$invalid);
});
scope.$on('show-errors-reset', function() {
$timeout(function() {
el.removeClass('has-error');
}, 0, false);
});
}
}
});
.form-group .help-block {
display: none;
}
.form-group.has-error .help-block {
display: inline;
}
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<form name="claimForm" ng-submit="save()">
<h3>PERSON</h3>
<div class="col-md-6">
<div class="form-group form-caller" show-errors>
<label class="control-label">First Name<span class="help-block" ng-if="claimForm.callerFirstName.$error.required"><i>[required]</i></span>
</label>
<input type="text" name="callerFirstName" ng-model="vm.caller.person.firstName" class="form-control" required="" />
</div>
</div>
<div class="col-md-6">
<div class="form-group form-caller" show-errors>
<label class="control-label">Last Name<span class="help-block" ng-if="claimForm.callerLastName.$error.required"><i>[required]</i></span>
</label>
<input type="text" name="callerLastName" ng-model="vm.caller.person.lastName" class="form-control" required="" />
</div>
</div>
<hr />
<h3>ADDRESS</h3>
<div class="col-md-6">
<div class="form-group" show-errors>
<label class="control-label">Address Line 1<span class="help-block" ng-if="claimForm.addressOne.$error.required"><i>[required]</i></span>
</label>
<input type="text" name="addressOne" ng-model="vm.caller.address.lineOne" class="form-control" required="" />
</div>
</div>
<div class="col-md-6">
<div class="form-group" show-errors>
<label class="control-label">Address Line 2<span class="help-block" ng-if="claimForm.addressTwo.$error.required"><i>[required]</i></span>
</label>
<input type="text" name="addressTwo" ng-model="vm.caller.address.lineTwo" class="form-control" required="" />
</div>
</div>
<hr />
<input type="submit" id="submit" value="SUBMIT" class="btn btn-primary btn-lg" />
{{vm | json }}
</form>
<h2>Summary</h2>
<div id="person">
<h3>PERSON </h3>
</div>
<hr />
<div id="address">
<h3>ADDRESS</h3>
</div>
</body>
Thanks in Advance

How do I prevent form submission in Angularjs if I am submitting the form using enter key?

I have applied validation to my form (It has only two fields) but don't know how to prevent it from submitting,Current flow is: After pressing enter key the student's name and marks are added on localstorage and are displayed on the screen from there but I am unable to prevent empty data from submitting.
These are my js functions:
$scope.searchEnter = function() {
if (event.which == 13 && $scope.student != "") {
$scope.addStudent();
}
};
$scope.addStudent = function() {
if ($scope.marks > 65) {
var pass = true;
} else {
pass = false;
}
$scope.students.push({ 'studentName': $scope.student, 'Marks': parseInt($scope.marks), 'pass': pass });
$scope.student = '';
$scope.marks = '';
localStorage['studentsList'] = JSON.stringify($scope.students);
};
This is the html part:
<div class="row">
<div class="col-xs-12">
<form class="form-horizontal" novalidate name="studentForm" >
<div class="form-group">
<label class="col-sm-2 control-label" for="student_name">Student's Name</label>
<div class="col-sm-5">
<input ng-model="student" ng-keyup="searchEnter()" type="text" class="form-control" id="student_name" ng-required="true" name="stdname">
<div ng-show="studentForm.stdname.$touched && studentForm.stdname.$invalid">
<small style="color:red; display:block;">Enter a valid name </small>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="student_marks">Marks obtained</label>
<div class="col-sm-5">
<input ng-model="marks" ng-keyup="searchEnter()" type="number" class="form-control" id="student_marks" ng-required="true">Press ENTER to insert student's data in the table.</div>
</div>
</form>
</div>
</div>
Supposing that your fields are correctly validating, to prevent the submit you could use ngDisabled directive, as below:
<button type="submit" ng-disabled="form.$invalid">Submit</button>
EDIT: Since the OP provided the full code I was able to give the correct answer, that is:
Change the check to:
if (event.which == 13 && $scope.student && $scope.marks) {
Snippet working based on your code:
(function() {
angular
.module('app', [])
.controller('MainCtrl', MainCtrl);
MainCtrl.$inject = ['$scope'];
function MainCtrl($scope) {
$scope.students = [];
$scope.searchEnter = function() {
if (event.which == 13 && $scope.student && $scope.marks) {
$scope.addStudent();
}
};
$scope.addStudent = function() {
console.log('addStudent called');
$scope.students.push({
'studentName': $scope.student,
'Marks': $scope.marks,
'pass': $scope.marks > 65
});
$scope.student = '';
$scope.marks = '';
localStorage['studentsList'] = JSON.stringify($scope.students);
};
}
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body ng-controller="MainCtrl">
<div class="row">
<div class="col-xs-12">
<form class="form-horizontal" novalidate name="studentForm">
<div class="form-group">
<label class="col-sm-2 control-label" for="student_name">Student's Name</label>
<div class="col-sm-5">
<input ng-model="student" ng-keyup="searchEnter()" type="text" class="form-control" id="student_name" ng-required="true" name="stdname">
<div ng-show="studentForm.stdname.$touched && studentForm.stdname.$invalid">
<small style="color:red; display:block;">Enter a valid name </small>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="student_marks">Marks obtained</label>
<div class="col-sm-5">
<input ng-model="marks" ng-keyup="searchEnter()" type="number" class="form-control" id="student_marks" ng-required="true">Press ENTER to insert student's data in the table.</div>
</div>
</form>
</div>
</div>
</body>
</html>
Tips:
The ngModel $scope.marks is already a number, you don't need to to do any parse, so you can have 'Marks': $scope.marks.
The check of pass can simply reduced to: 'pass': $scope.marks > 65

Save input values in reactive variables (Meteor)

I am using reactive vars to manage visibility of my input fields depenging on user's choice select. But when I choose one option, write anything in shown input, then go to the second option, and finally when I come back to the firs one, the input value disappears. Is there any way to keep that data untill confirm button pressing to confirm once all the fields values under all the options?
Here are two input groups that are displayed, when option is set:
<template name="addTour">
<label class="control-label col-xs-4" for="tour-dropdown">Программа</label>
<div class="dropdown col-xs-8 form-group form-horisontal">
<select class="form-control" id="tour-dropdown">
<option value="a">A</option>
<option value="b">B</option>
</select>
</div>
{{#if a}}
<div class="container-fluid">
{{> textfield label='a option' id='transfer-city-from'}}
{{> confirm add='a option'}}
</div>
{{/if}}
{{#if b}}
<div class="container-fluid">
{{> textfield label='b option' id='transfer-city-from'}}
{{> confirm add='b option'}}
</div>
{{/if}}
And some JS here that manages reactive variables to do all that job:
Template.addTour.onCreated( function () {
this.a = new ReactiveVar( false );
this.b = new ReactiveVar( false );
Template.addTour.helpers( {
a: function () {
return Template.instance().a.get();
},
b: function () {
return Template.instance().b.get();
}
}
});
Template.addTour.events( {
'change select': function ( event, template ) {
if ( $( event.target ).val() === "a" ) {
template.a.set( true );
} else {
template.a.set( false );
};
if ( $( event.target ).val() === "b" ) {
template.b.set( true );
} else {
template.b.set( false );
};
}
});
Or I shoud better use display:block and display:none ?
Thanks in advance for any suggestions.
So, I managed to resolve my problem with jQuery and it's hide() / show() options.
Here is the code:
<template name="addTour">
<label class="control-label col-xs-4" for="tour-dropdown">Программа</label>
<div class="dropdown col-xs-8 form-group form-horisontal">
<select class="form-control" id="tour-dropdown" >
<option value="a">A</option>
<option value="b">B</option>
</select>
</div>
<div class="container-fluid" id="a">
<div class="row">
<div class="col-sm-4">
<form class='form-horizontal'>
<div class="form-group">
<h1>A option</h1>
{{> timepicker label='время прибытия' id='transfer-time-a'}}
</div>
</form>
</div>
</div>
</div>
<div class="container-fluid" id="b">
<div class="row">
<div class="col-sm-4">
<form class='form-horizontal'>
<div class="form-group">
<h1>B option</h1>
{{> timepicker label='время прибытия' id='transfer-time-b'}}
</div>
</form>
</div>
</div>
</div>
And jQuery works for me in this view:
Dropdown = $('#tour-dropdown');
$('#a').hide();
$('#b').hide();
select = this.value;
Dropdown.change(function() {
if ($(this).val() === 'a') {
$('#a').show();
console.log('A option');
} else $('#a').hide();
if ($(this).val() === 'b') {
$('#b').show();
console.log('B option');
} else $('#b').hide();// hide div if value is not "custom"
});
It works fine and keep values inside all the hidden inputs, so I can submit all of them once.

AngularJS Validation trouble

I have a form which seems to work well on the most part. However, my selects are playing up a bit, and I cant seem to submit the form. My form looks like
<form ng-submit="submit(emailform)" name="emailform" method="post" action="" class="form-horizontal emailType" role="form">
<div class="form-group" ng-class="{ 'has-error': emailform.inputTitle.$invalid && submitted }">
<label for="inputTitle" class="col-lg-4 control-label">Title</label>
<div class="col-lg-8">
<select ng-model="formData.inputTitle" data-ng-options="title for title in titles" id="inputTitle" required>
<option value="">Please select</option>
</select>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error': emailform.inputName.$invalid && submitted }">
<label for="inputName" class="col-lg-4 control-label">First Name(s)</label>
<div class="col-lg-8">
<input ng-model="formData.inputName" type="text" class="form-control" id="inputName" name="inputName" placeholder="First Name(s)" required>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error': emailform.inputLinks.$invalid && submitted }">
<label for="inputLinks" class="col-lg-4 control-label">Link to be sent</label>
<div class="col-lg-8">
<select ng-model="formData.inputLinks" data-ng-options="link for link in links" id="inputLinks" required>
<option value="">Please select</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button type="submit" class="btn btn-default" ng-disabled="submitButtonDisabled">
Send Message
</button>
</div>
</div>
</form>
<p ng-class="result" style="padding: 15px; margin: 0;">{{ resultMessage }}</p>
So a simple form with two selects and one input. My Controller looks like the following
'use strict';
/* Controllers */
function EmailViewCtrl($scope, $http) {
$scope.titles =
[
"Mr",
"Mrs",
"Miss",
"Ms",
"Dr"
];
$scope.links =
[
"email1",
"email2",
"email3",
"email4",
"email5"
];
$scope.result = 'hidden'
$scope.resultMessage;
$scope.formData; //formData is an object holding the name, email, subject, and message
$scope.submitButtonDisabled = false;
$scope.submitted = false; //used so that form errors are shown only after the form has been submitted
$scope.submit = function(emailform) {
$scope.submitted = true;
$scope.submitButtonDisabled = true;
if (emailform.$valid) {
$http({
method : 'POST',
url : 'backend/email.php',
data : $.param($scope.formData), //param method from jQuery
headers : { 'Content-Type': 'application/x-www-form-urlencoded' } //set the headers so angular passing info as form data (not request payload)
}).success(function(data){
console.log(data);
if (data.success) { //success comes from the return json object
$scope.submitButtonDisabled = true;
$scope.resultMessage = data.message;
$scope.result='bg-success';
} else {
$scope.submitButtonDisabled = false;
$scope.resultMessage = data.message;
$scope.result='bg-danger';
}
});
} else {
$scope.submitButtonDisabled = false;
$scope.resultMessage = 'Failed <img src="http://www.chaosm.net/blog/wp-includes/images/smilies/icon_sad.gif" alt=":(" class="wp-smiley"> Please fill out all the fields.';
$scope.result='bg-danger';
}
}
}
EmailViewCtrl.$inject = ['$scope', '$http'];
Now the problem is, my selects on their default option (please select) have a red border around them on page load. Obviously this should not appear until they submit the form without an option selected.
Secondly, if I provide the form with valid data, the submit button does not seem to become active. How can I make this active?
Lastly, at the moment, everything is in one controller. Should I move things like the selects values into their own controller and what would be the best way to achieve this?
Thanks
You can use form.input.$dirty to check if an input has been touched and only in that case show a validation error.
ng-class="{ 'has-error': emailform.inputName.$invalid && emailform.inputName.$dirty }"
See the example below for a working copy of your code:
var app = angular.module("app", []);
app.controller("EmailViewCtrl", function EmailViewCtrl($scope, $http) {
$scope.titles = [
"Mr",
"Mrs",
"Miss",
"Ms",
"Dr"
];
$scope.links = [
"email1",
"email2",
"email3",
"email4",
"email5"
];
$scope.result = 'hidden'
$scope.resultMessage;
$scope.formData; //formData is an object holding the name, email, subject, and message
$scope.submitButtonDisabled = false;
$scope.submitted = false; //used so that form errors are shown only after the form has been submitted
$scope.submit = function(emailform) {
$scope.submitted = true;
$scope.submitButtonDisabled = true;
if (emailform.$valid) {
alert("POST!");
} else {
$scope.submitButtonDisabled = false;
$scope.resultMessage = 'Failed <img src="http://www.chaosm.net/blog/wp-includes/images/smilies/icon_sad.gif" alt=":(" class="wp-smiley"> Please fill out all the fields.';
$scope.result = 'bg-danger';
}
}
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="EmailViewCtrl">
<form ng-submit="submit(emailform)" name="emailform" method="post" action="" class="form-horizontal emailType" role="form">
<div class="form-group" ng-class="{ 'has-error': emailform.inputTitle.$invalid && emailform.inputTitle.$dirty }">
<label for="inputTitle" class="col-lg-4 control-label">Title</label>
<div class="col-lg-8">
<select class="form-control" ng-model="formData.inputTitle" data-ng-options="title for title in titles" id="inputTitle" required>
<option value="">Please select</option>
</select>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error': emailform.inputName.$invalid && emailform.inputName.$dirty }">
<label for="inputName" class="col-lg-4 control-label">First Name(s)</label>
<div class="col-lg-8">
<input ng-model="formData.inputName" type="text" class="form-control" id="inputName" name="inputName" placeholder="First Name(s)" required>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error': emailform.inputLinks.$invalid && emailform.inputLinks.$dirty }">
<label for="inputLinks" class="col-lg-4 control-label">Link to be sent</label>
<div class="col-lg-8">
<select class="form-control" ng-model="formData.inputLinks" data-ng-options="link for link in links" id="inputLinks" required>
<option value="">Please select</option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-2 col-lg-10">
<button type="submit" class="btn btn-default" ng-disabled="submitButtonDisabled">
Send Message
</button>
</div>
</div>
</form>
<p ng-class="result" style="padding: 15px; margin: 0;">{{ resultMessage }}</p>
</div>

meteor rerender login form after log in

I have a Meteor and login form like this:
<template name="index">
<h3>Index Page</h3>
{{#if currentUser}}
You are logged in!<br>
Dashboard
{{else}}
{{> loginForm}}
{{/if}}
</template>
<template name="loginForm">
<div class="container">
<div class="row col-md-offset-2 col-sm-offset-2">
<div class="container col-md-2 col-sm-2">
<h4>Login</h4>
</div>
<div class="container col-md-4 sol-sm-4">
<h4><small>or register</small></h4>
</div>
</div>
<!--div class="row"-->
<form class="form-horizontal" id="formLogin">
<div class="form-group">
<div class="col-md-2 col-sm-2">
<label for="inputEmail" class="control-label pull-right">Email</label>
</div>
<div class="col-md-4 col-sm-4">
<input type="email" class="form-control" id="inputEmail" placeholder="Email">
</div>
</div>
<div class="form-group">
<div class="col-md-2 col-sm-2">
<label for="inputPassword" class="control-label pull-right">Password</label>
</div>
<div class="col-md-4 col-sm-4">
<input type="password" class="form-control" id="inputPassword" placeholder="Password">
</div>
</div>
<!--<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
</label>
</div>
</div>
</div>-->
<div class="form-group">
<div class="col-md-offset-2 col-sm-offset-2 col-md-10 col-sm-6">
<input type="submit" class="btn btn-default" value="Sign in">
</div>
</div>
</form>
<!--/div-->
</div>
<!-- END loginForm END -->
</template>
Here the JavaScript code for template:
Template.loginForm.events({
"submit #formLogin": function(e, t) {
e.preventDefault();
//console.log("Form login submitted");
var loginForm = $(e.currentTarget),
email = loginForm.find("#inputEmail").val(),
password = loginForm.find("#inputPassword").val();
//console.log("Email:" + email + "\n" + "Password:" + password);
//++++++ Validation
var trimInput = function(val) {
return val.replace(/^\s*|\s*$/g, "");
};
isEmailValid = trimInput(email).length > 5 ? true : false
//console.log(isEmailValid);
isPasswordValid = password.length > 0 ? true : false
//console.log(isPasswordValid);
//------
if (isEmailValid && isPasswordValid) {
Meteor.loginWithPassword(email, password, function(err) {
if (err) {
if (err.message === "User not found [403]") {
console.log("User does not exist.");
} else if (err.message === "Incorrect password [403]") {
console.log("Incorrect password");
} else if (err.message === "Match failed [400]") {
console.log("Match failed");
} else {
console.log(err.message)
}
} else {
return true;
}
});
} else {
console.log("Incorrect data");
};
}
});
After success login user shouldn't see the form. But if I refresh the page login form appear for 1-1,5 seconds and dissapear. How avoid this?
I had the same issue and this is how I solved it.
put:
if (Meteor.userId()) Router.go("main");
return false;
after your Meteor.loginWithPassword call
ie, for iron router and "main" as the template to render after login
When you do a page refresh the server will log in again as you are creating a new session in effect, it will automatically pick up the fact that you were previously logged in and log you in using those details. However for that period it will not have a userId and currentUser is null. It will however have a loggingIn state of true Meteor.loggingIn() which you are not checking for. To avoid confusion, check for the loggingin state and then show a loading screen or spinner to indicate something is happening.
You can create a global loggingIn handlebars helper:
if (Handlebars) {
Handlebars.registerHelper('loggingIn', function () {
return Meteor.loggingIn();
});
}
and then use that to display a loading/spinner template whilst the server is processing the login request after your page refresh:
{{#if currentUser}}
You are logged in!<br>
Dashboard
{{else}}
{{#if loggingIn}}
{{> loading}}
{{else}}
{{> loginForm}}
{{/if}}
{{/if}}
Which should solve the problem of the app presenting the login screen to the user on first page call/refresh and causing confusion, it will also let them know it is doing something whilst it is working away in the background to log them in.
If you still see the login form it should be really really minimal and flash up very quickly before reverting to either login or loading template.

Categories

Resources