Angular form.$invalid submit button not working - html

So my validation is working the way it should with the exception of the buttons. I want them grayed out with opacity until all is valid and not sure if I have the ng-class set correctly and/or the ng-disabled set correctly or both.
The issue here is more per functionality. I have some fields that show when other fields dropdowns are selected to a particular item. For instance, "Age" is only shown is a particular option is selected whereas with all the other options, it does not show. I show my HTML and then my CSS below.
Yes, is a lengthy form, but hoping you all can help!
My form:
<form class="addClaim" name="claimForm" novalidate ng-submit="saveClaim(claimInfo)" data-ng-model="claimInfo">
<div class="form-group col-md-6 naviaInp">
<label for="beneSelect">Select your benefit</label>
<select class="form-control" name="beneSelect" id="beneSelect" ng-model="benefit" ng-options="item.descr for item in claim" required>
<option value="">Please select a benefit....</option>
</select>
<input type="hidden" ng-model="claimInfo.benefitId" ng-change="{{ claimInfo.benefitId = benefit.id }}"/>
</div>
<div ng-show="claimForm.beneSelect.$dirty && claimForm.beneSelect.$error.required" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>this is a required field</span></p>
</div>
<div class="form-group col-md-8 naviaInp" ng-show="benefit.askSecIns == true" >
<label for="secInc">Do you have secondary insurance</label>
<div>
<label class="radio-inline"><input type="radio" name="optradioSecIns" data-ng-model="claimInfo.isSecIns" value="true">yes</label>
<label class="radio-inline"><input type="radio" name="optradioSecIns" data-ng-model="claimInfo.isSecIns" value="false">no</label>
</div>
</div>
<div class="checkbox form-group col-md-8 naviaInp" ng-show="benefit.askResidual == true">
<p>If you have a Health Care FSA, any residual amount not covered by the HRA will automatically be entered into the FSA. If you do not wish to have the residual amount entered into your Health Care FSA, please indicate </p>
<label><input type="checkbox" name="residualAmount" data-ng-value="true" ng-model="claimInfo.isNoResId">
<p>No, please do not enter residual amounts into my Health Care FSA</p>
</label>
</div>
<div class="form-group col-md-6 naviaInp" ng-show="benefit.expenseTypes != null">
<label for="beneTypeSelect">Select type of service</label>
<select class="form-control" name="expenseType" id="beneServiceSelect" ng-model="expense" ng-options="item.descr for item in benefit.expenseTypes" required>
<option value="">Please select a service....</option>
</select>
<input type="hidden" ng-model="claimInfo.expenseTypeId" ng-change="{{ claimInfo.expenseTypeId = expense.id }}" />
</div>
<div ng-show="claimForm.expenseType.$dirty && claimForm.expenseType.$error.required" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>this is a required field</span></p>
</div>
<div class="form-group naviaInp">
<label for="start">Date of Service</label>
<div>
<input type="text" class="form-control" name="startDate" id="start" placeholder="--/--/----" data-ng-model="claimInfo.fromDate" style="width: 200px;" required>
<span style="padding-left: 20px; padding-right: 20px;">To</span>
<input type="text" class="form-control" id="end" placeholder="--/--/---- (optional)" data-ng-model="claimInfo.toDate" style="width: 200px;">
</div>
</div>
<div ng-show="claimForm.startDate.$dirty && claimForm.startDate.$error.required" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>this is a required field</span></p>
</div>
<div class="form-group col-md-6 naviaInp">
<label for="providerName">Provider Name</label>
<input type="text" name="providerName" class="form-control " id="providerName" ng-maxlength="100" data-ng-model="claimInfo.provider" required>
</div>
<div ng-show="claimForm.providerName.$dirty && claimForm.providerName.$error.required" style="clear: both; margin-top: 8px;">
<p class="claimError" style="color: #ab2328;"><i class="fa fa-exclamation-circle"></i><span style="padding-left: 10px; font-size: 14px; margin-bottom:: 25px;">this is a required field</span></p>
</div>
<div ng-show="claimForm.providerName.$dirty && claimForm.providerName.$error.maxlength" class="errorContainer" style="clear: both; margin-top: 8px;">
<p class="claimError" style="color: #ab2328;"><i class="fa fa-exclamation-circle"></i><span style="padding-left: 10px; font-size: 14px; margin-bottom:: 25px;">must be less than 100 characters</span></p>
</div>
<div class="form-group col-md-6 naviaInp" ng-model="claimInfo.depId" ng-show="benefit.dependents != null">
<label for="beneTypeSelect">Select dependant</label>
<select class="form-control" name="depSelect" id="beneDepSelect" ng-model="dependent" ng-options="item.name for item in benefit.dependents" required>
<option value="">Please select a dependant....</option>
</select>
<input type="hidden" ng-model="claimInfo.depId" ng-change="{{ claimInfo.depId = dependent.id }}" required />
</div>
<div ng-show="claimForm.depSelect.$dirty && claimForm.depSelect.$error.required" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>this is a required field</span></p>
</div>
<div class="form-group col-md-6 naviaInp" name="forWhom" ng-show="benefit.dependents == null">
<label for="forWhom">For Whom</label>
<input type="text" class="form-control" id="forWhom" ng-maxlength="100" data-ng-model="claimInfo.who" required >
</div>
<div ng-show="claimForm.forWhom.$dirty && claimForm.forWhom.$error.required" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>this is a required field</span></p>
</div>
<div ng-show="claimForm.forWhom.$dirty && claimForm.forWhom.$error.maxlength" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>a maximum of 100 characters are allowed</span></p>
</div>
<div class="form-group col-md-4 naviaInp" name="age" ng-show="benefit.benefCode == 'DCFSA'">
<label for="age">Age</label>
<input type="text" class="form-control" id="age" data-ng-model="claimInfo.age" ng-maxlength="50" required>
</div>
<div ng-show="claimForm.age.$dirty && claimForm.age.$error.required" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>this is a required field</span></p>
</div>
<div ng-show="claimForm.age.$dirty && claimForm.age.$error.maxlength" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>a maximum of 50 characters are allowed</span></p>
</div>
<div class="form-group col-md-4 naviaInp">
<label for="claimAmount">Amount</label>
<input type="number" name="amount" class="form-control" id="claimAmount" data-ng-model="claimInfo.amount" required ng-pattern="/^\d{1,4}(\.\d{0,2})?$/">
</div>
<div ng-show="claimForm.amount.$dirty && claimForm.amount.$error.required" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>this is a required field</span></p>
</div>
<div ng-show="claimForm.amount.$dirty && claimForm.amount.$error.pattern" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>the amount must be between $0 and $10,000</span></p>
</div>
<div class="form-group col-md-8 naviaInp">
<label for="claimComment">Comments</label>
<textarea class="form-control" name="comment" rows="5" id="claimComment" placeholder="optional" ng-maxlength="500" data-ng-model="claimInfo.comments">
</textarea>
</div>
<div ng-show="claimForm.comment.$dirty && claimForm.comment.$error.maxlength" class="errorContainer">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>a maximum of 500 characters are allowed</span></p>
</div>
<div class="fileArea col-md-8 naviaInp">
<div>
<p>Drag and drop or upload your documentation. Remember, we cannot review your claim without at least one piece of proper documentation for each claimed expense listed above. Be sure your documentation shows the date of service, type of service, and cost of service.</p>
</div>
<div ngf-drop ngf-select ng-model="files" class="drop-box"
ngf-drag-over-class="'dragover'" ngf-multiple="true" ngf-allow-dir="true"
accept="image/*,application/pdf"
ngf-pattern="'image/*,application/pdf'"><p>Drag and drop your documents here or click to search for your documents and upload</p></div>
<div ngf-no-file-drop><p>File Drag/Drop is not supported for this browser</p></div>
<div>
<p>Files:</p>
</div>
<div>
<ul>
<li ng-repeat="f in files" style="font:smaller">{{f.name}} {{f.$error}} {{f.$errorParam}} <a class="deleteHandle" ng-click="deleteFile($index)">×</a> </li>
</ul>
</div>
</div>
<div style="padding-bottom: 150px; clear: both;">
<div class="checkbox col-md-8">
<label><input type="checkbox" value="" ng-model="checked"><p>By checking this box, you agree to Navia's <a class="naviaLink" data-toggle = "modal" data-target = "#tcModal" >Terms and Conditions</a>.</p></label>
</div>
<div class="form-group" style="clear: both;">
<input type="button" class="naviaBtn naviaBlue" ng-show="editMode == true" ng-click="updateClaim(claimInfo)" value="+ update claim" ng-disabled="claimForm.$invalid" ng-class="{'disabled-class': claimForm.$invalid}">
<input type="button" class="naviaBtn naviaBlue" ng-show="editMode == false" ng-click="saveClaim()" value="+ add another claim" ng-disabled="claimForm.$invalid" ng-class="{'disabled-class': claimForm.$invalid}">
<input type="button" class="naviaBtn naviaBlue" ng-disabled="!checked && claimForm.$invalid" ng-show="editMode == false" ng-class="{'disabled-class': !checked}" ng-click="saveAllClaims()" value="submit claim(s)">
</div>
<div>
<input type="button" class="naviaBtn naviaRed" ng-click="cancel()" value="cancel">
</div>
<div data-ng-hide="message == ''" data-ng-class="(savedSuccessfully) ? 'alert alert-success' : 'alert alert-danger'">
{{message}}
</div>
</div>
</form>
I did abbreviate code as much as I thought I could but still show what I am doing.
And my CSS:
.disabled-class {
background-color: #999999;
opacity: .30;
}
.disabled-class:hover {
background-color: #999999;
opacity: .30;
}
input.ng-invalid.ng-dirty {
border: 1px solid red;
}
.errorContainer {
clear: both;
margin-top: 8px;
}
.claimError {
color: #ab2328;
}
.claimError > span {
padding-left: 10px;
font-size: 14px;
margin-bottom:: 25px;
}
.disabled {
background-color: #999999;
opacity: .30;
}
.disabled:hover {
background-color: #999999;
opacity: .30;
}
What should happen here is that the buttons are grayed and disabled until all required fields have input and that the input is within the parameters set.

The angular form has both validity and invalidity properties.
Actually, all angular form elements do, they are nestable and invalidity bubbles up. If an element is invalid, automatically all the ancestors up to the form itself have $invalid == true.
You can call the form by its name in the $scope and the properties are $valid, respectively $invalid.
Here's the relevant code for your form:
<form name="claimForm">
// your form logic here
<button type="submit" ng-disabled="claimForm.$invalid" />
</form>
UPDATE: If your form doesn't behave the way you want, you should debug it:
divide your form into fieldsets, according to the logic of your form
when each of your fieldset are valid, your form is valid
test each fieldset sepparately and add some divs to display the $valid or $invalid value of each fieldset until you sort it out
I also think you are adding an unnecessary level of complexity to your problem by using inline conditional logic at html level. I'd keep it in the controller, where it's a lot easier to follow and structure.
Whenever something doesn't behave the way you expect it to, console.log(it).
One more thing: once dirty, an element will stay $dirty regardless of being or not disabled, unless you call $setPristine() on it. So you should probably try to avoid using $dirty in yoru logic, it might produce unncecessary confusion.
Most times, value.length and/or $valid are enough to make forms work.

Related

Validating three inputs that they should not be same

I am using Boostrap to validate my registration form and I want user to provide three user name which should not be same. Now I cant prevent submitting but the boostrap form still showing that input field is correct, how can I mark it to be invalid for user to know which part they wrong?
html
<form class="needs-validation" novalidate>
<h6 class="d-inline-block pt-3">Please enter 3 choices for login username:</h6>
<div class="col-md-12 mb-3">
<label for="sys_user_first" class="form-label">
First Choice
<i class="fa-solid fa-star-of-life required-field fa-xs"></i>
</label>
<input type="text" class="form-control" id="sys_user_first" required>
<div class="invalid-feedback">
Please fill in the first choice and three choices should not be same.
</div>
<label for="sys_user_second" class="form-label">
Second Choice
<i class="fa-solid fa-star-of-life required-field fa-xs"></i>
</label>
<input type="text" class="form-control" id="sys_user_second" required>
<div class="invalid-feedback">
Please fill in the second choice and three choices should not be same.
</div>
<label for="sys_user_third" class="form-label">
Third Choice
<i class="fa-solid fa-star-of-life required-field fa-xs"></i>
</label>
<input type="text" class="form-control" id="sys_user_third" required>
<div class="invalid-feedback">
Please fill in the third choice and three choices should not be same.
</div>
</div>
</form>
JS
form.addEventListener('submit', function (event) {
if (form.checkValidity() === false||$("#d_sys_user_first").val() === $("#sys_user_second").val() || $("#sys_user_first").val() === $("#sys_user_third").val() || $("#sys_user_second").val() === $("#sys_user_third").val()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
}, false);

Make input required upon clicking specific radio button

I need to make a specific input field required based on the choice of a specific radio button. I have tried ng-required but doesn't seem to work.
I want to make the phone number field required if one chooses the payment method4 with the model ng-model="selected_payment_method=CC
<form ng-submit="proceed_payment()" type="post" name="paymentForm" novalidate>
<div class="col s12">
<div class="col s12">
<input name="payment" ng-model="selected_cc_method" class="with-gap" id="payment4" type="radio"
value="CC" ng-click="selected_payment_method = 'CC'"/>
<label class="fund-project-payment-method-label" for="payment4">CC</label>
</div>
</div>
</div>
<div class="col s12 shipping-details">
<div class="fund-project-additional fund-project-personal-details">
Personal Details
</div>
<label for="email" class="fund-project-personal-details-label">Email</label>
<input placeholder="Email" id="email" type="email" ng-model="email" class="validate" required>
<!--
Phone Number & Name a required field as well
-->
<label for="display_name" class="fund-project-personal-details-label">Name</label>
<input placeholder="Name" id="display_name" ng-model="name" type="text"
class="validate" required>
<label for="phone_number" class="fund-project-personal-details-label">Phone Number</label>
<input placeholder="Phone Number" id="phone_number" type="text" ng-model="phone_number" ng-required="selected_payment_method === 'CC'">
<input placeholder="Your message." id="personal_message" ng-model="personal_message" type="text"
class="validate" maxlength="200">
<span class="personal-message-text">
This will be displayed on the campaign page.
</span>
</div>
<div class="col s12 right">
<button type="submit" class="waves-effect waves-light btn-large orange white-text proceed-payment"
disabled="selected_payment_method == undefined || paymentForm.$invalid || selected_reward_total_amount == 0">
Next: Pay
<i class="fa fa-chevron-right" ng-if="!proccess_payment_spinner"></i>
<div class="preloader-wrapper small active right payment-loader" ng-if="proccess_payment_spinner">
<div class="spinner-layer spinner-white-only">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
</button>
This is what I have done on the angular side to make sure payment is done.
What am I not doing right?
$scope.proceed_payment = function () {
$scope.proccess_payment_spinner = true;
if ($scope)
var payment_method = $('input:radio[name=payment]:checked').val();
if ($scope.selected_reward_details.limit_reward_amount &&
parseInt($scope.selected_reward_details.selected_quantity) > parseInt($scope.selected_reward_details.remaining_quantity)) {
$('#heading').html("Too many rewards!");
$('#message').html("Unfortunately the amount of rewards you've selected exceeds the number available.");
$('#error_modal').openModal();
return;
}
if (payment_method === "CC") {
ProjectPaymentService.initiateCCPayment(
$scope.project.id,
$scope.selected_reward_details.id,
$('#email').val(),
$('#display_name').val(),
$('#phone_number').val(),
$('#personal_message_display_name').val(),
$('#personal_message').val(),
parseInt($scope.selected_reward_details.selected_quantity),
parseFloat($scope.selected_reward_details.custom_amount),
parseFloat($scope.selected_reward_details.shipping_fee),
parseFloat($scope.selected_reward_details.reward_amount * $scope.selected_reward_details.selected_quantity),
parseFloat($scope.selected_reward_total_amount),
$('#address_1').val(),
$('#address_2').val(),
$('#country').val(),
$('#postcode').val(),
$('#city').val(),
$('#region').val()
).then(
function successHandler(data) {
$scope.proccess_payment_spinner = false;
var project_funding_id = angular.fromJson(data.data);
$location.path("mpesa_details/" + project_funding_id);
},
function errorHandler(data) {
$scope.proccess_payment_spinner = false;
console.log(angular.fromJson(data.data));
});
Radio type input does not need ng-click to set its value:
<input type="radio" name="payment" ng-model="selected_cc_method"
class="with-gap" id="payment4" value="CC" />
Now you can use selected_cc_method with ng-required:
<input placeholder="Phone Number" id="phone_number" type="text"
ng-model="phone_number" ng-required="selected_cc_method === 'CC'">
You can see here that when radio button is clicked, phone number input becomes required:
DEMO
You have two variables you are working with;
selected_cc_method
and
selected_payment_method
I would drop the ng-click and set the model of the radio and use the radio button value for the ng-required instead of trying to use another variable for this.
<input name="payment" ng-model="selected_payment_method" class="with-gap"
id="payment4" type="radio" value="CC"/>
<label class="fund-project-payment-method-label" for="payment4">CC</label>
<input placeholder="Phone Number" id="phone_number" type="text"
ng-model="phone_number"
ng-required="selected_payment_method === 'CC'">

form elements not clickable

I am developing a system I have been asked to do but the form elements are not clickable to enter any info in the fields, I have tried moving the form tag to above the very first div in the code below in case it was the issue but did not work unfortunately. I am not sure what else to try, can someone have a look at the code below please
Update: I have got the form elements working by adding zindex: 9999; to .form-group class in the CSS but now the datetimepicker is appearing behind the select dropdown menu. I have uploaded a screenshot of the issue to the link below
Here is a screenshot of my issue:
My code:
<link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
<div class="col-lg-12" id="detail">
<form name="addData" id="addData" action="" method="post">
<div class="row">
<div class="form-group col-lg-3">
<input type="hidden" name="eventID" id="eventID" class="form-control">
<label for="StartDate">Start Date: </label>
<input type="date" class="form-control" required name="StartDate" id="StartDate" />
</div>
<div class="form-group col-lg-3">
<label for="StartTime" style="margin: 0 0 15px 0;">Start Time: </label>
<div class='input-group date' id='datetimepicker3'>
<input name="StartTime" id="StartTime" type='text' required class="form-control" />
<span class="input-group-addon">
<i class="fa fa-clock-o"></i>
</span>
</div>
<script type="text/javascript">
$(function() {
$('#datetimepicker3').datetimepicker({
format: 'LT'
});
});
</script>
</div>
<div class="form-group col-lg-3">
<label for="StartDate">End Date: </label>
<input type="date" required class="form-control" name="EndDate" id="EndDate" />
</div>
<div class="form-group col-lg-3">
<label for="EndTime" style="margin: 0 0 15px 0;">End Time: </label>
<div class='input-group date' id='datetimepicker4'>
<input name="EndTime" id="EndTime" required type='text' class="form-control" />
<span class="input-group-addon">
<i class="fa fa-clock-o"></i>
</span>
</div>
<script type="text/javascript">
$(function() {
$('#datetimepicker4').datetimepicker({
format: 'LT'
});
});
</script>
</div>
</div>
<div class="row">
<div class="form-group col-lg-3">
<label for="riders_name">Riders Name: </label>
<select class="form-control" style="height: 34px;" required name="riders_name" id="riders_name"></select>
</div>
<div class="form-group col-lg-3">
<label for="horses_name">Horses Name : </label>
<select class="form-control" style="height: 34px;" required name="horses_name" id="horses_name">
<option value="">--Empty--</option>
</select>
</div>
<div class="form-group col-lg-3">
<label for="instructor_name">Instructor Name : </label>
<select class="form-control" style="height: 34px;" required name="instructor_name" id="instructor_name">
<option value="">--Empty--</option>
</select>
</div>
<div class="form-group col-lg-3">
<label for="groom_name">Groom Name : </label>
<select class="form-control" style="height: 34px;" required name="groom_name" id="groom_name">
<option value="">--Empty--</option>
</select>
</div>
</div>
<br>
<div class="row">
<div class="form-group col-lg-9">
<label for="comments">Comments : </label>
<textarea name="comments" id="comments" class="form-control"></textarea>
</div>
<div class="form-group col-lg-3">
<label for="Repeat">Repeat : </label>
<select class="form-control" style="height: 34px;" required name="Repeat" id="Repeat">
<option value="0">none</option>
<option value="1">Daily</option>
<option value="2">Weekly</option>
<option value="3">Monthly</option>
</select>
</div>
</div>
<div class="row">
<div class="form-group col-lg-1">
<button type="submit" class="btn btn-primary" name="submit" id="submit">Submit</button>
</div>
<div class="form-group col-lg-1">
<button type="submit" class="btn btn-danger" name="cancel" id="cancel">Cancel</button>
</div>
<div class="form-group col-lg-5">
</div>
<div class="form-group col-lg-5">
</div>
</div>
</form>
</div>
<script>
$.getJSON("fullcalendar/getriders.php", function(data) {
var select = $('#riders_name'); //combo/select/dropdown list
if (select.prop) {
var options = select.prop('options');
} else {
var options = select.attr('options');
}
$('option', select).remove();
$.each(data, function(key, value) {
options[options.length] = new Option(value['name'], value['id']);
});
});
$.getJSON("fullcalendar/getinstructors.php", function(data) {
var select = $('#instructor_name'); //combo/select/dropdown list
if (select.prop) {
var options = select.prop('options');
} else {
var options = select.attr('options');
}
$('option', select).remove();
$.each(data, function(key, value) {
options[options.length] = new Option(value['name'], value['id']);
});
});
$.getJSON("fullcalendar/getgrooms.php", function(data) {
var select = $('#groom_name'); //combo/select/dropdown list
if (select.prop) {
var options = select.prop('options');
} else {
var options = select.attr('options');
}
$('option', select).remove();
$.each(data, function(key, value) {
options[options.length] = new Option(value['name'], value['id']);
});
});
</script>
I see several empty <select></select> tags in your form. I suspect you are intending text fields there? If so you need to replace <select></select> with <input type="text" />.
Example, this:
<label for="riders_name">Riders Name: </label>
<select class="form-control" style="height: 34px;" required name="riders_name" id="riders_name"></select>
...should be:
<label for="riders_name">Riders Name: </label>
<input class="form-control" type="text" style="height: 34px;" required name="riders_name" id="riders_name" />
Select drop down always higher z-index set by default by browsers. You have two row one underneath other. You should in top row set higher z-index value with position: relative; then I hope it will work as expected.
Add CSS code with following way:
.higher-z-index {
postion: relative; // This line help z-index work relatively
z-index: 999;
}
Your markup will be something like that:
<div class="row higher-z-index">
.....
....
</div>
<div class="row">
.....
....
</div>
Why this approach:
You should keep it mind this is dose not matter how much z-index value applied in .form-group selector it will work for only sibling elements. But in your case it is going behind of next row elements because modern browsers set by default higher z-index in each next sibling elements until we set explicitly. So underneath row getting higher z-index than top row. So it is dose not matter how many higher z-index value are applied inside of top row container, all will go behind of next row container.

Setting the form.invalid property to true from a HTML select element in Angular 2

I have created a basic form that contains various input elements (mainly text) all of the text boxes have the 'Required' attribute set plus a simple regex pattern. Using Angular 2's Form directive I am disabling a button if the field text inputs are empty or the regex is not met. This works as expected. However, thrown into the mix is a 'Select' element with 2 'Option' child elements. The first is my default and the second my data bound list. I would like to set the form.invalid property to true if the initial:
<option value="default">Select a department...</option>
is selected from the combo box.
My issue as it stands is that if I enter valid data into all of my text boxes but leave the combo box as 'Select a department...' the form.invalid property is false and the button is enabled. As 'Select a department...'
is not a valid value I need the button to become disabled if that is selected?
Current HTML select code as it stands
<form class="form-inline" #form="ngForm" novalidate>
<div class="col-sm-12">
<div class="form-group" [class.has-error]="AddfirstName.invalid && AddfirstName.touched">
<label class="col-sm-12 control-label" for="AddfirstName">First Name:</label>
<div class="col-sm-12">
<input class="form-control" #AddfirstName="ngModel" required pattern="\D+" placeholder="First Name" [ngModel]="firstName" (ngModelChange)="firstLetterOfFirstNameToUpperCase($event)"
name="firstName">
<div class="alert alert-danger" *ngIf="AddfirstName.invalid && AddfirstName.touched ">First Name Is mandatory and cannot contain numbers</div>
</div>
</div>
<div class="form-group" [class.has-error]="AddlastName.invalid && AddlastName.touched">
<label class="col-sm-12 control-label" for="AddlastName">Last Name:</label>
<div class="col-sm-12">
<input class="form-control" #AddlastName="ngModel" required pattern="\D+" placeholder="Last Name" [ngModel]="lastName" (ngModelChange)="firstLetterOfLastNameToUpperCase($event)"
name="lastName" />
<div class="alert alert-danger" *ngIf="AddlastName.invalid && AddlastName.touched ">Last Name Is mandatory and cannot contain numbers </div>
</div>
</div>
</div>
<div class="col-sm-12">
<div class="form-group" [class.has-error]="AdduserName.invalid && AdduserName.touched">
<label class="col-sm-12 control-label" for="AdduserName">User Name:</label>
<div class="col-sm-12">
<input class="form-control" #AdduserName="ngModel" required placeholder="User Name" ngModel name="userName" />
<div class="alert alert-danger" *ngIf="AdduserName.invalid && AdduserName.touched">User Name Is mandatory</div>
</div>
</div>
<div class="form-group"[class.has-error]="Addpassword.invalid && Addpassword.touched">
<label class="col-sm-12 control-label" for="Addpassword">Password:</label>
<div class="col-sm-12">
<input type="password" class="form-control" #Addpassword="ngModel" required placeholder="Password" ngModel name="password" />
<div class="alert alert-danger" *ngIf="Addpassword.invalid && Addpassword.touched ">Password Is mandatory</div>
</div>
</div>
</div>
<div class="col-sm-12">
<div class="form-group" [class.has-error]="hasDepartmentError">
<label class="col-sm-12 control-label" for="Department">Department:</label>
<div class="col-sm-12">
<select class="form-control" id="Department" #AddDepartment="ngModel" [(ngModel)]="addDepartment"
[ngModelOptions]="{standalone: true}"
(change)="validateDepartment(AddDepartment.value)"
(blur)="validateDepartment(AddDepartment.value)">
<option value="default">Select a department...</option>
<option *ngFor="let department of departmentList">{{department.name}}</option>
</select>
<div class="alert alert-danger" *ngIf="hasDepartmentError">Department Is mandatory</div>
</div>
</div>
</div>
<div class="col-sm-12">
<button class="btn btn-primary" (click)="addUser(AddfirstName.value, AddlastName.value, AdduserName.value, Addpassword.value, AddDepartment.value);
AddfirstName.value=null;AddlastName.value=null;Addpassword.value=null;AdduserName.value=null;" [disabled]="form.invalid">Add</button>
</div>
</form>
</div>
</div>
Remove the value from your first option and mark your select required:
<select class="form-control" id="Department" #AddDepartment="ngModel" [(ngModel)]="addDepartment"
[ngModelOptions]="{standalone: true}"
(change)="validateDepartment(AddDepartment.value)"
(blur)="validateDepartment(AddDepartment.value)"
required>
<option>Select a department...</option>
<option *ngFor="let department of departmentList">{{department.name}}</option>
</select>
Seems you have forgotten to put required on your select. Your two-way binding also seems to take away the default value of the drop down list, so I would loose that and just use ngModel instead. You really don't need to use two-way binding in forms, the form names take care of that, and when you submit the form, you have a nice object to work with.
when you loose the ngModel, you also drop the ngModelOptions and use the name attribute instead, which would be needed for the form.
I'm also unsure about the validateDepartment method. You wouldn't need it, as you can validate this in the template.
So all in all the final snippet of your select could look like this:
<select required #addDepartment="ngModel" name="addDepartment" ngModel>
<option value="">Select a department...</option>
<option *ngFor="let department of departmentList">{{department.name}}</option>
</select>
<div *ngIf="addDepartment.errors?.required">
Department required!
</div>
Here's a
Plunker
to play with, where you can also see the object created from the form! :)

Style font awesome icon to the right of input

Having a difficult time forcing this icon to be at the right of the input rather than dropping below. Have changed col number, put in div, etc.. But nothing. Here is how it looks now:
My code for this is (sample doesn't show closing form tag):
<form class="pptReg" role="form" name="pptReg" novalidate>
<h1 style="padding-top: 60px; color: #ab2328;">Participant Information</h1>
<div class="form-group col-md-3 naviaInp" style="padding-top: 30px;">
<label for="empCode">Employer Code</label>
<input type="text" name="empCode" class="form-control" id="empCode" data-ng-model="pptregistration.coCode" ng-required="true" maxlength="3" autofocus ng-blur="getEmpIdType(true);">
<a class="questionIcon" href="#"><i class="fa fa-question-circle col-md-2 fa-2x" style="float: right;"></i></a>
<div ng-show="(pptReg.$submitted || pptReg.empCode.$touched) && pptReg.empCode.$error.required">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>This is a required field.</span></p>
</div>
<div ng-show="(pptReg.$submitted || pptReg.empCode.$touched) && empIdType == ''">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>The Employer Code is invalid.</span></p>
</div>
</div>
It is simply a font awesome icon I am trying to add to the right of the input there. Am using Bootstrap 3 for layout.
Ideas or suggestions (I have come through many in my own head!)?
Thanks much.
First you need to restrict the width of the input so that there's enough space next to it for the icon. Then you need to set the input and icon to display:inline-block; also, remove the col-md-2 class from the icon as it is unnecessary. Finally, add vertical-align:middle; to the icon so that it's vertically aligned with the input.
HTML:
<form class="pptReg" role="form" name="pptReg" novalidate="">
<h1 style="padding-top: 60px; color: #ab2328;">Participant Information</h1>
<div class="form-group col-md-3 naviaInp" style="padding-top: 30px;">
<label for="empCode">Employer Code</label>
<input type="text" name="empCode" class="form-control" id="empCode" data-ng-model="pptregistration.coCode" ng-required="true" maxlength="3" autofocus="" ng-blur="getEmpIdType(true);">
<a class="questionIcon" href="#"><i class="fa fa-question-circle col-md-2 fa-2x"></i></a>
<div ng-show="(pptReg.$submitted || pptReg.empCode.$touched) && pptReg.empCode.$error.required">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>This is a required field.</span></p>
</div>
<div ng-show="(pptReg.$submitted || pptReg.empCode.$touched) && empIdType == ''">
<p class="claimError"><i class="fa fa-exclamation-circle"></i><span>The Employer Code is invalid.</span></p>
</div>
</div>
</form>
CSS:
.form-control {
display:inline-block;
width:90%;
}
a.questionIcon {
display:inline-block;
vertical-align:middle;
}
Bootply
Add display: inline; as follow to question mark:
<a class="questionIcon" href="#"><i class="fa fa-question-circle col-md-2 fa-2x" style="float: right; display:inline;"></i></a>
The class .form-control makes the empCode input as a block element. You'll need to add styling to the input to allow for other elements to reside on the same line as it (ie float:left; display:inline-block;).