Validate a form ng-required - javascript

I have a form like that :
<div class="row" id="yesAuth">
<div class="col-md-6" ng-class="{ 'has-error': invalid.basicAuthForBackendUsername, 'has-success': valid.basicAuthForBackendUsername}">
<div class="form-group">
<label for="basicAuthForBackendUsername">basic auth username *</label>
<input type="text" name="basicAuthForBackendUsername" class="form-control" placeholder="basic auth username" ng-model="api.basicAuthForBackendUsername" ng-required="true">
<span id="helpBlock" class="help-block" ng-show="help.basicAuthForBackendUsername.required">basic auth username is required.</span> </div>
</div>
</div>
I show/hide a div in terms of a value of a select. When the value is "no" I hide the div and when it's "yes" I show the div.
When I validate my form and I choose the value "yes", the field in the hidden div doesn't take into account the ng-required. (so the next page appears whereas I don't want it because it's empty).
$(function() {
$('#yesAuth').hide();
$("#basicAuth").change(function() {
if ($("#basicAuth option:selected").val() == 'yes') {
$('#yesAuth').show();
$('#basicAuthForBackendUsername').attr("ng-required", "true");
alert("VOILA" + $('#basicAuthForBackendUsername').attr("ng-required"))
} else {
$('#yesAuth').hide();
$('#basicAuthForBackendUsername').attr("ng-required", "false");
alert("VOILA" + $('#basicAuthForBackendUsername').attr("ng-required"));
}
});
});
How can I solve my problem?
All the code:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<div class="jumbotron" ng-show="firstPage">
<h3>API builder</h3>
<form action="/publish" method="POST" name="userForm">
<div class="panel panel-default">
<div class="panel-heading"><h4>Offer</h4></div>
<div class="panel-body">
<div class="row">
<div class="col-md-6">
<div class="form-group" ng-class="{ 'has-error': invalid.apiName, 'has-success': valid.apiName}">
<label for="apiName">api name *</label>
<input type="text" name="apiName" class="form-control" placeholder="api name" ng-model="api.apiName" ng-required="true">
<span id="helpBlock" class="help-block" ng-show="help.apiName.required">api name is required.</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group" ng-class="{ 'has-error': invalid.version, 'has-success': valid.version}">
<label for="version">version *</label>
<select name="version" id="version" class="form-control" ng-init="api.version = api.version || ''" ng-model="api.version" ng-required="true">
<option value=""></option>
<option value="beta">beta</option>
<option value="v1">v1</option>
<option value="v2">v2</option>
<option value="v3">v3</option>
<option value="v4">v4</option>
</select>
<span id="helpBlock" class="help-block" ng-show="help.version.required">version is required.</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6" ng-class="{ 'has-error': invalid.backendServiceUrl, 'has-success': valid.backendServiceUrl}">
<div class="form-group" >
<label for="backendServiceUrl">backend service URL *</label>
<input type="text" name="backendServiceUrl" class="form-control" placeholder="backend service URL" ng-model="api.backendServiceUrl" ng-required="true">
<span id="helpBlock" class="help-block" ng-show="help.backendServiceUrl.required">backend service URL is required.</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group" id="basicAuth">
<label for="basicAuth">basic auth info</label>
<select name="basicAuth" class="form-control" ng-init="api.basicAuth = api.basicAuth || 'no'" ng-model="api.basicAuth" id="basicAuth" >
<option value="no">no</option>
<option value="yes">yes</option>
</select>
</div>
</div>
</div>
<div class="row" id="yesAuth">
<div class="col-md-6" ng-class="{ 'has-error': invalid.basicAuthForBackendUsername, 'has-success': valid.basicAuthForBackendUsername}">
<div class="form-group" >
<label for="basicAuthForBackendUsername">basic auth username *</label>
<input type="text" id="basicAuthForBackendUsername" name="basicAuthForBackendUsername" class="form-control" placeholder="basic auth username" ng-model="api.basicAuthForBackendUsername" >
<span id="helpBlock" class="help-block" ng-show="help.basicAuthForBackendUsername.required">basic auth username is required.</span>
</div>
</div>
<div class="col-md-6" ng-class="{ 'has-error': invalid.basicAuthForBackendPassword, 'has-success': valid.basicAuthForBackendPassword}">
<div class="form-group" >
<label for="basicAuthForBackendPassword">basic auth password *</label>
<input type="text" id="basicAuthForBackendPassword" name="basicAuthForBackendPassword" class="form-control" placeholder="basic auth password" ng-model="api.basicAuthForBackendPassword">
<span id="helpBlock" class="help-block" ng-show="help.basicAuthForBackendPassword.required">basic auth password is required.</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group" ng-class="{ 'has-error': invalid.apiDescription, 'has-success': valid.apiDescription}">
<label for="apiDescription">api description *</label>
<input type="text" name="apiDescription" class="form-control" placeholder="description..." ng-model="api.apiDescription" ng-required="true">
<span id="helpBlock" class="help-block" ng-show="help.apiDescription.required">api description is required.</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group" ng-class="{ 'has-error': invalid.useProxy, 'has-success': valid.useProxy}">
<label for="useProxy">backend exposed on the Internet *</label>
<select name="useProxy" class="form-control" ng-init="api.useProxy = api.useProxy || 'yes'" ng-model="api.useProxy" ng-required="true">
<option value="yes">yes</option>
<option value="no">no</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="iconUrl">icon URL</label>
<input type="text" name="iconUrl" class="form-control" placeholder="icon URL" ng-model="api.iconUrl">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="statusUrl">get status URL</label>
<input type="text" name="statusUrl" class="form-control" placeholder="get status URL" ng-model="api.statusUrl">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group" ng-class="{ 'has-error': invalid.approvalMode, 'has-success': valid.approvalMode}">
<label for="approvalMode">approval mode *</label>
<select name="approvalMode" class="form-control" ng-init="api.approvalMode = api.approvalMode || 'auto'" ng-model="api.approvalMode" ng-required="true">
<option value="auto">auto</option>
<option value="manual">manual</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group" ng-class="{ 'has-error': invalid.orangeInternalContact, 'has-success': valid.orangeInternalContact}">
<label for="orangeInternalContact">orange internal contact *</label>
<input type="text" name="orangeInternalContact" class="form-control" placeholder="orange internal contact" ng-model="api.orangeInternalContact" ng-required="true">
<span id="helpBlock" class="help-block" ng-show="help.orangeInternalContact.required">orange internal contact is required.</span>
</div>
</div>
</div>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h4><input type="checkbox" ng-model="api.swagger"> Generation from swagger</h4></div>
<div class="panel-body" ng-show="api.swagger">
<div class="form-group" ng-class="{ 'has-error': invalid.swaggerSource, 'has-success': valid.swaggerSource}">
<label for="generateFromIntegrationSwaggerUrl">
<input type="radio" name="swaggerSource" ng-model="api.swaggerSource" value="url" checked ng-required="api.swagger && api.swaggerSource != 'file'">
Swagger URL hosted by the integration backend
</label>
<span id="helpBlock" class="help-block" ng-show="help.swaggerSource.required">One option is required</span>
</div>
<div class="form-group" ng-class="{ 'has-error': invalid.swaggerSource, 'has-success': valid.swaggerSource}">
<label for="swaggerFile">
<input type="radio" name="swaggerSource" ng-model="api.swaggerSource" value="file" ng-required="api.swagger && api.swaggerSource != 'url'">
Upload Swagger 2.0 JSON file
</label>
<span id="helpBlock" class="help-block" ng-show="help.swaggerSource.required">One option is required</span>
<input type="file" file-model="myFile" name="swaggerFile" class="btn btn-info">
</div>
</div>
</div>
<button ng-click="publish()" class="btn btn-lg btn-primary" type="button">Publish</button>
<p ng-show="validatingStatus==='loading'">
<div ng-show="validatingStatus==='loading'" class="alert alert-info" role="alert">Please wait. Operation in progress. <img src="<c:url value="/resources/images/ajax-loader.gif" />"></div>
</p>
</form>
</div>
<script>
$(function () {
$('#yesAuth').hide();
$("#basicAuth").change(function () {
if($("#basicAuth option:selected").val() == 'yes'){
$('#yesAuth').show();
$('#basicAuthForBackendUsername').attr("ng-required","true");
$('#basicAuthForBackendPassword').attr("ng-required","true");
alert("VOILA" + $('#basicAuthForBackendPassword').attr("ng-required"))
}
else{
$('#yesAuth').hide();
$('#basicAuthForBackendUsername').removeAttr("ng-required");
$('#basicAuthForBackendPassword').removeAttr("ng-required");
alert("VOILA" + $('#basicAuthForBackendPassword').attr("ng-required"));
}
});
});
</script>
Thanks a lot.

As you are using ngModel to bind value api.basicAuth, You can directly pass Angular expression to ngRequired directive.
use it your view as
<input type="text" ng-required="api.basicAuth == 'yes'" ng-model="api.basicAuthForBackendUsername">

Related

integrating dropzone with normal form

I have successfully integrated dropzone with my form using jquery. However, I have an issue with validation of the other form inputs. It seems the other form inputs do not respect the validation such as "required". I also tried using parsley for validation but does not work. when I remove the dropzone field, the validation works well.
Here is the form.
<form class="form-vertical"
id="createPropertyForm"
enctype="multipart/form-data"
method="POST"
>
<div class="col-md-12 col-lg-12 col-sm-12" >
<div class="col-md-6">
<div class="form-group">
<label class=" control-
label">Country</label>
<div class="inputGroupContainer">
<input id="country"
name="country" placeholder="Country" class="form-control" required
value="" type="text">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="control-
label">County</label>
<div
class="inputGroupContainer">
<input id="county"
name="county" placeholder="County" class="form-control" required value=""
type="text">
</div>
</div>
</div>
</div>
<div class="col-md-12 col-lg-12 col-sm-12" >
<div class="col-md-6">
<div class="form-group">
<label class=" control-
label">Town</label>
<div class=" inputGroupContainer">
<input id="town" name="town"
placeholder="Town" class="form-control" required value="" type="text">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="control-
label">Postcode</label>
<div class="inputGroupContainer">
<input id="postcode"
name="postcode" placeholder="Postcode" class="form-control" required
value=""
type="text">
</div>
</div>
</div>
</div>
<div class="col-md-12 col-lg-12 col-sm-12" >
<div class="col-md-6">
<div class="form-group">
<label class=" control-
label">Description</label>
<div class=" inputGroupContainer">
<textarea id="description"
name="description" placeholder="Description" class="form-control"
required="true" value="" type="text"></textarea>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="control-
label">Address</label>
<div class="inputGroupContainer">
<input id="address" name="address"
placeholder="Address" class="form-control" required value="" type="text">
</div>
</div>
</div>
</div>
<div class="col-md-12 col-lg-12 col-sm-12" >
<div class="col-md-6">
<div class="form-group">
<label class=" control-
label">Bedrooms</label>
<div class=" inputGroupContainer">
<select class=" form-control"
name="bedrooms" id="bedrooms" required>
</select>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="control-label
">Bathrooms</label>
<div class=" inputGroupContainer">
<select
class="selectpicker bathrooms form-control" name="bathrooms"
id="bathrooms"
required>
</select>
</div>
</div>
</div>
</div>
<div class="col-md-12 col-lg-12 col-sm-12" >
<div class="col-md-6">
<div class="form-group">
<label class=" control-
label">Price</label>
<div class="inputGroupContainer">
<input id="price" name="price"
placeholder="Price" class="form-control" required value="" type="number">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="control-
label">Property Type</label>
<div class=" inputGroupContainer">
<select
class="selectpicker form-control" name="propertyType" id="propertyType">
<option
value="">Choose type</option>
<?php
foreach
($propertyTypes as $propertyType) {
?>
<option value="<?=
$propertyType->id ?>"><?= $propertyType->title ?></option>
<?php
}
?>
</select>
</div>
</div>
</div>
</div>
<div class="col-md-12 col-lg-12 col-sm-12" >
<div class="col-md-6">
<div class="form-group">
<label class=" control-
label">Type</label>
<div class="col-md-12">
<div class="col-md-6 ">
<label><input type="radio"
name="type" class="form-control type" required>Sale</label>
</div>
<div class="col-md-6">
<label><input type="radio"
name="type" class="form-control type" required>Rent</label>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="control-
label">Upload Image</label>
<div class=" inputGroupContainer">
<div class="dropzone"
id="create-dropzone" >
<div class="fallback">
<input name="file"
type="file" required/>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-6">
<div class="dropzone-previews"></div>
</div>
</div>
<div class="col-md-6 col-sm-6">
<button class="btn btn-success btn-lg"
type="submit" id="submitCreateForm"> Submit </button>
</div>
</form>.
Here is the jquery code:
// Parsley for form validation
$('#createPropertyForm').parsley();
$('#editPropertyForm').parsley();
Dropzone.options.createDropzone = {
url: `${baseUrl}administrator/properties`,
autoProcessQueue: false,
parallelUploads: 1,
maxFiles: 1,
maxFileSize:2048,
uploadMultiple: false,
acceptedFiles: "image/*",
init: function () {
var submitButton = document.querySelector("#submitCreateForm");
var wrapperThis = this;
submitButton.addEventListener("click", function (e) {
e.preventDefault();
if (wrapperThis.files.length) {
wrapperThis.processQueue();
} else {
wrapperThis.submit();
}
});
this.on("addedfile", function (file) {
var removeButton = Dropzone.createElement("<button class='btn btn-block btn-danger'><i class='fa-times fa'></button>");
removeButton.addEventListener("click", function (e) {
e.preventDefault();
e.stopPropagation();
wrapperThis.removeFile(file);
});
file.previewElement.appendChild(removeButton);
});
this.on('sending', function (data, xhr, formData) {
formData.append("country", $("#country").val());
formData.append("county", $("#county").val());
formData.append("town", $("#town").val());
formData.append("postcode", $("#postcode").val());
formData.append("description", $("#description").val());
formData.append("address", $("#address").val());
formData.append("bathrooms", $("#bathrooms").val());
formData.append("price", $("#price").val());
formData.append("bedrooms", $("#bedrooms").val());
formData.append("propertyTypeId", $("#propertyType").val());
formData.append("type", $(".type").val());
});
this.on('success', function (files, response) {
toastr.success(response.message);
setTimeout(function () {
location.reload();
}, 1000);
});
this.on('error', function (file, error, xhr) {
file.status = 'queued';
if (xhr.status === 422){
toastr.error('An error occurred, please confirm that you have filled all inputs and try again');
}else{
toastr.error('An error occurred');
}
});
this.on("maxfilesexceeded", function(file) {
wrapperThis.removeFile(file);
});
}
};

ERROR TypeError: Cannot read property 'email' of null

I am writing a form validation for email and for it it is giving following error - ERROR TypeError: Cannot read property 'email' of null.
Following is the HTML code for Angular 5 Template driven form.
<form name="form" #myForm="ngForm" (ngSubmit) = "onSubmit()">
<div class="form-group">
<label for="firstName">First Name*</label>
<input type="text" class="form-control" name="firstName" [(ngModel)]="firstName" #firstname="ngModel" required minlength="6" />
<div *ngIf="firstname.touched && firstname.invalid">
<div *ngIf="firstname.invalid && firstname.errors.required" class="alert alert-danger">First name is mandatory</div>
<div *ngIf="firstname.invalid && firstname.errors.minlength" class="alert alert-danger">First name must have minimum 6 characters</div>
</div>
<div *ngIf="myForm.submitted && firstname.invalid">
<div *ngIf="firstname.invalid && firstname.errors.required">First name is mandatory</div>
</div>
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input type="text" class="form-control" name="lastName" [(ngModel)]="lastName" #lastname="ngModel" required />
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="myemail" [(ngModel)]="email"
#myemail="ngModel" required myemail/>
<div *ngIf="myemail.touched">
<div *ngIf="myemail.invalid && myemail.errors?.required" class="alert alert-danger">Email is required</div>
<div *ngIf="myemail.errors.email && !myemail.errors.required" class="alert alert-danger">Email is not valid</div>
</div>
</div>
<div class="form-group">
<label for="selectcity">City</label>
<select name="city" class="form-control" [(ngModel)] = "cityvalue" required #cityselect = "ngModel">
<option value="Pune">Pune</option>
<option value="Mumbai">Mumbai</option>
<option value="Delhi">Delhi</option>
<option value="Surat">Surat</option>
</select>
<div *ngIf="cityselect.touched && cityselect.invalid">
<div *ngIf="cityselect.invalid && cityselect.errors.required" class="alert alert-danger">City name is mandatory</div>
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" [(ngModel)]="password" #mypassword="ngModel" minlength="6"/>
</div>
<div class="form-group">
<button class="btn btn-primary">Register</button>
</div>
</form>
Following is the code for email validation
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="myemail" [(ngModel)]="email"
#myemail="ngModel" required myemail/>
<div *ngIf="myemail.touched">
<div *ngIf="myemail.invalid && myemail.errors?.required" class="alert alert-danger">Email is required</div>
<div *ngIf="myemail.errors.email && !myemail.errors.required" class="alert alert-danger">Email is not valid</div>
</div>
</div>
If I use "myemail.errors?.email" It works fine but does not show message "Email is not valid".
If I use "myemail.errors.email" it throws error shown above or in title.
I tried to use the pattern "pattern="[a-z0-9._%+-]+#[a-z0-9.-]+.[a-z]{2,4}$" " It worked for email.
Following is my question:
Why in template driven form of angular email is null error thrown?
And How can we solve it.
Should be change to
<input type="email" class="form-control" name="myemail" [(ngModel)]="myemail"
#myemail="ngModel" required />

AngularJS won't validate input on form elements that are ng-show hidden

I'm working on an accordion like registration form and every time I progress to the next step of registration by hiding the first part of the form and expanding the next with ng-show, the elements on vm.registerForm.(elementName) are undefined. From what I read in the documentation angular only applies a class to these elements, so why are they undefined when validating a form at the final step?
I haven't been able to find any documentation on this.
HTML Template:
<form name="vm.registerForm">
<div class="accordion">
<div class="accordion-section expanded"
ng-show="vm.formList.indexOf('playerInfo') != -1 || vm.formList.indexOf('login') != -1">
<div class="section-title" ng-click="vm.gotoMode('playerInfo')">User info</div>
<div class="section-content" ng-show="vm.mode.playerInfo || vm.mode.login">
<div class="flex-form">
<div class="flex-form-group" ng-if="vm.mode.playerInfo">
<label>Already have an account? Just log in!</label>
<div class="button" ng-click="vm.gotoMode('login')">Log in</div>
</div>
<div class="flex-form-group dummy"></div>
<div class="flex-form-group dummy"></div>
<div class="flex-form-group dummy"></div>
</div>
<div class="flex-form" ng-if="vm.mode.playerInfo">
<div class="flex-form-group">
<label for="user_name">Username</label>
<input username-checker type="text" ng-model="vm.username" name="user_name">
</div>
<div class="flex-form-group">
<label for="first">First name</label>
<input type="text" ng-model="vm.firstName" name="first" ng-required="true">
</div>
<div class="flex-form-group">
<label for="last">Last name</label>
<input type="text" ng-model="vm.lastName" name="last" ng-required="true">
</div>
<div class="flex-form-group" ng-if="vm.gameManager.game.name == 'League of Legends'">
<label for="summoner">Summoner Name</label>
<input type="text" ng-model="vm.summoner" name="summoner" summoner>
<br>
</div>
<div class="flex-form-group">
<label for="email">Email</label>
<input type="email" ng-model="vm.email" name="email" ng-required="true">
</div>
<div class="flex-form-group">
<label for="birthday">Day of birth (MM/DD/YYYY)</label>
<input type="text" ng-model="vm.birthday" name="birthday" ng-required="true" birthdate>
</div>
<div class="flex-form-group">
<select ng-model="vm.sex" name="sex" ng-required="true">
<option value="">Gender</option>
<option value="male">Male</option>
<option value="female">Female</option>
<option value="other">Other</option>
<option value="not_specified">Prefer not to answer</option>
</select>
</div>
<div class="flex-form-group">
<label for="zip">Zip code</label>
<input type="text" ng-model="vm.zip" name="zipcode" ng-required="true" zipcode>
</div>
<div class="flex-form-group">
<label for="phone">Phone number (optional)</label>
<input type="text" ng-model="vm.phone" name="phone" ng-required="false" phone-number>
</div>
<div class="flex-form-group">
<label for="password">Password</label>
<input type="password" ng-model="vm.password" name="password" ng-minlength="6" ng-maxlength="20">
</div>
<div class="flex-form-group">
<label for="password2">Password (again)</label>
<input type="password" ng-model="vm.password2" name="password2" ng-minlength="6" ng-maxlength="20">
</div>
<div class="flex-form-group">
<div class="checkbox-holder">
<input class='checkbox' type="checkbox" name='showPlayerName' ng-model="vm.showPlayerName">
<label for="full_name">Show Real Name on Bracket</label>
</div>
</div>
<div class="flex-form-group">
<div class="checkbox-holder">
<input class='checkbox' type="checkbox" name='type' value="true" ng-model="vm.type">
<label for="spec">Spectator</label>
</div>
</div>
<div class="flex-form-group">
<div class="checkbox-holder">
<input class='checkbox' type="checkbox" id='accept' value="true" ng-required="vm.regMode != 'user'"
ng-model="vm.accept">
<label for="accept">Accept Terms of Service</label>
</div>
</div>
<div class="flex-form-group">
<a class="aside-link" href="" ng-click="vm.showTOS = true">View TOS</a>
</div>
</div>
<!-- Continue -->
<div class="button" ng-click="vm.next()" ng-if="!(vm.formList.length - 1 == vm.modeIterator)">
Next
</div>
<!-- If there aren't anymore steps to complete -->
<div class="button" ng-click="vm.next()" ng-if="(vm.formList.length - 1 == vm.modeIterator)">
Confirm
</div>
</div>
</div>
<div class="accordion-section" ng-class="{expanded: vm.mode.teams}" ng-if="vm.formList.indexOf('payment') != -1">
<div class="section-title" ng-click="vm.gotoMode('teams'); vm.gotoTeamMode('preference')">Teams</div>
<div class="section-content">
...
</div>
</div>
</div>
Validation Code:
function userFormValid() {
var valid = false;
if (vm.regMode == "user") {
valid = true;
} else if (vm.regMode == "anon" || vm.regMode == "admin") {
// All the parts of the form.
valid = vm.registerForm.zipcode.$valid && vm.registerForm.first.$valid && vm.registerForm.last.$valid;
valid &= vm.registerForm.email.$valid && vm.registerForm.sex.$valid && vm.registerForm.birthday.$valid;
valid &= (vm.accept == true) && vm.registerForm.user_name.$valid && vm.registerForm.password.$valid;
valid &= vm.password == vm.password2;
valid &= vm.registerForm.password2.$valid;
// Let's show a message if this is invalid
if (vm.password != vm.password2) {
vm.showMessage('Passwords must match.');
return false;
}
}
return valid;
}
Running the above function at the end of registration will not show any of the elements as defined.
I overlooked an ng-if that was further down in the DOM. If anyone is wondering, the angular.js FromController does not remove an NgModelController unless the child scope of an element is destroyed.

Cordova app form input fields lagging in showing data while entering

I have created a cordova app using node, angular, sqlite. The app consist of multipage form. When i fill the form then input fields are lagging means they are taking time to show the entered data. Can anyone tell me the reasons why these issues comes.
My farm page is quite big means it consist large no. of fields which are divided in four parts and i am showing them 1 by 1 after by making others hide and then submitting it in the end.
this is the form
<form name="signupForm" data-ng-submit="gotoAddress()">
<div class="col-sm-12 col-xs-12 top-bottom-border"> <span class="heading">Personal Info</span>
</div>
<div class="col-sm-12 col-xs-12">
<div class="form-group form-group-custom">
<label class="form-tags-info-page" for="name">Name</label>
<br>
<input class="form-control" id="input-elements-info-page" placeholder="name" type="text" name="ufname" ng-pattern="/^[a-zA-Z0-9\-\s\,]{1,100}$/" ng-model="myForm.name" required>
<div class="help-block" spellcheck="false" autocomplete="off">
<p style="color: red" ng-show="signupForm.ufname.$dirty && signupForm.ufname.$touched && signupForm.ufname.$error.required">Name is required</p>
<p style="color: red" ng-show="signupForm.ufname.$dirty && signupForm.ufname.$touched && signupForm.ufname.$error.pattern">Enter a valid Name</p>
</div>
</div>
<div class="col-sm-12 col-xs-12 remove-all-padding">
<div class="form-group col-sm-6 col-xs-6 remove-all-padding age-group" ng-class="{ 'has-error' : submitted && signupForm.age.$invalid }">
<label class="form-tags-info-page" for="age">Age(in year)</label>
<br>
<input name="age" class="form-control" id="input-elements-info-page" type="number" ng-model="myForm.age" min="14" max="120" required>
<span class="help-block" style="color:red" ng-show="signupForm.age.$dirty && signupForm.age.$invalid">
<span style="color:red" ng-show="signupForm.age.$error.required">Required!</span>
<span style="color:red" ng-show="signupForm.age.$error.min">Minimum 14</span>
<span style="color:red" ng-show="signupForm.age.$error.max">Invalid Age!</span>
</span>
</div>
<div class="form-group col-sm-6 col-xs-6 remove-all-padding sex-group pull-right">
<label class="form-tags-info-page" for="sex">Sex</label>
<br>
<select class="form-control" id="input-elements-info-page" ng-model="myForm.sex" required>
<option value="" selected disabled>Select Sex</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error' : submitted && signupForm.ownership.$invalid }">
<label class="form-tags-info-page">Ownership</label>
<select name="ownership" data-ng-model="myForm.ownership" id="input-elements-info-page" placeholder="Select Annual Income" class="form-control" required>
<option value="" selected disabled>Select Ownership</option>
<option value="Owner">Owner</option>
<option value="Successor">Successor</option>
<option value="Blood-relative">Blood-relative</option>
<option value="Contract-farmer">Contract-farmer</option>
</select>
<div ng-show="submitted && signupForm.ownership.$invalid" class="help-block">
<p ng-show="signupForm.ownership.$error.required">Annual Income is required</p>
</div>
</div>
<div class="form-group">
<label class="form-tags-info-page" for="name">Father's Name</label>
<br>
<input class="form-control" id="input-elements-info-page" placeholder="father's name" type="text" name="fname" ng-pattern="/^[a-zA-Z0-9\-\s\,]{1,100}$/" ng-model="myForm.fathername" required>
<div class="help-block">
<p style="color: red" ng-show="signupForm.fname.$dirty && signupForm.fname.$touched && signupForm.fname.$error.required">Father's Name is required</p>
<p style="color: red" ng-show="signupForm.fname.$dirty && signupForm.fname.$touched && signupForm.fname.$error.pattern">Enter a valid Father's Name</p>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error' : submitted && signupForm.mobile_no.$invalid }">
<label class="form-tags-info-page" for="mobile">Mobile Number</label>
<br>
<input class="form-control" id="input-elements-info-page" type="number" name="mobile_no" placeholder="Mobile No" ng-model="myForm.mobile_no" ng-minlength="10" ng-maxlength="10" ng-pattern="/^[7-9]{1}[0-9]{9}/" required>
<span class="help-block" style="color:red" ng-show="signupForm.mobile_no.$dirty && signupForm.mobile_no.$invalid">
<span style="color:red" ng-show="signupForm.mobile_no.$error.required">Required!</span>
<span style="color:red" ng-show="signupForm.mobile_no.$error.minlength">Too short!</span>
<span style="color:red" ng-show="signupForm.mobile_no.$error.maxlength">Too long!</span>
<span style="color:red" ng-show="signupForm.mobile_no.$error.pattern">Invalid Mobile Number</span>
</span>
</div>
<div class="form-group" ng-class="{ 'has-error' : submitted && signupForm.alt_mobile_no.$invalid }">
<label class="form-tags-info-page" for="mobile">Alternate Mobile Number</label>
<br>
<input class="form-control" id="input-elements-info-page" type="number" name="alt_mobile_no" placeholder="Alternate Mobile No" ng-model="myForm.alt_mobile_no" ng-minlength="10" ng-maxlength="10" ng-pattern="/^[7-9]{1}[0-9]{9}/" required>
<span class="help-block" style="color:red" ng-show="signupForm.alt_mobile_no.$dirty && signupForm.alt_mobile_no.$invalid">
<span style="color:red" ng-show="signupForm.alt_mobile_no.$error.required">Required!</span>
<span style="color:red" ng-show="signupForm.alt_mobile_no.$error.minlength">Too short!</span>
<span style="color:red" ng-show="signupForm.alt_mobile_no.$error.maxlength">Too long!</span>
<span style="color:red" ng-show="signupForm.alt_mobile_no.$error.pattern">Invalid Mobile Number</span>
</span>
</div>
<div class="form-group">
<label class="form-tags-info-page" for="email">Email Id(optional)</label>
<br>
<input class="form-control" id="input-elements-info-page" placeholder="Email" type="email" ng-pattern="/^[A-Za-z]+[a-z0-9._]+#[a-z]+\.[a-z.]{2,5}$/" ng-model="myForm.email">
<div class="help-block">
<p style="color: red" ng-show="signupForm.email.$dirty && signupForm.email.$touched && signupForm.email.$error.pattern">Enter a valid email address</p>
</div>
</div>
<div class="form-group">
<label class="form-tags-info-page" for="size">Family Size</label>
<br>
<select class="form-control" id="input-elements-info-page" ng-model="myForm.family_size" required>
<option value="" selected disabled>Select Family Size</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">>10</option>
</select>
</div>
<form class="form-inline col-sm-12 col-xs-12 remove-all-padding">
<div class="form-group col-sm-6 col-xs-6 age-group remove-all-padding">
<label class="form-tags-info-page" for="land">LandArea</label>
<br>
<input class="form-control" id="input-elements-info-page" style="width:100%;" type="number" required ng-model="myForm.l_area">
</div>
<div class="form-group col-sm-6 col-xs-6 remove-all-padding sex-group pull-right">
<label class="form-tags-info-page" for="size">Unit</label>
<br>
<select class="form-control" id="input-elements-info-page" style="width:100%;" ng-model="myForm.area_unit" required>
<option value="" selected disabled>Select Unit</option>
<option value="Acre">Acre</option>
<option value="Hactare">Hactare</option>
<option value="Bigha">Bigha</option>
</select>
</div>
</form>
<div class="form-group">
<label class="form-tags-info-page" for="size">Language Preference</label>
<br>
<select class="form-control" id="input-elements-info-page" ng-model="myForm.language" required>
<option value="" selected disabled>Select Language</option>
<option value="english">English</option>
<option value="hindi">Hindi</option>
<option value="others">Others</option>
</select>
</div>
<form class="form-inline col-sm-12 col-xs-12 remove-all-padding">
<div class="form-group col-sm-6 col-xs-6 remove-all-padding ">
<label class="form-tags-info-page col-sm-12 col-xs-12" for="uid_type">ID Type</label>
<br>
<select class="form-control col-sm-12 col-xs-12" id="input-elements-info-page" style="width:100%;" ng-model="myForm.farmerid_type">
<option value="" selected disabled>Select id Type</option>
<option value="Aadhar">Aadhar</option>
<option value="VoterID">VoterID</option>
<option value="Driving Licence">Driving Licence</option>
</select>
</div>
<div class="form-group col-sm-6 col-xs-6 remove-all-padding sex-group">
<label class="form-tags-info-page" for="uid_no">ID No.</label>
<br>
<input class="form-control" id="input-elements-info-page" type="text" style="width:100%;" ng-model="myForm.farmeruid_no" required>
</div>
</form>
<div class="col-sm-12 col-xs-12 remove-all-padding">
<div class="col-sm-12 col-xs-12 camera-img-wrapp">
<div class="col-sm-6 col-xs-6"> <span ng-click="takePic()" class="glyphicon glyphicon-camera camera-pic"></span>
</div>
<div class="col-sm-6 col-xs-6"> <span ng-click="takeScan();" class="glyphicon glyphicon-camera camera-pic"></span>
</div>
</div>
<div class="col-sm-12 col-xs-12">
<div class="col-sm-6 col-xs-6" style="text-align:center;font-weight:bold;">
<p class="form-tags-info-page">Take Pic</p>
</div>
<div class="col-sm-6 col-xs-6" style="text-align:center;font-weight:bold;">
<p class="form-tags-info-page">Take Scan</p>
</div>
</div>
</div>
<div class="form-group col-sm-12 col-xs-12 remove-all-padding" ng-show="imageSrc || scanSrc">
<div class="col-sm-4 col-xs-4 col-sm-offset-2 col-xs-offset-2"> <span ng-show="imageSrc"><img src="" id="myImage" style="width:100px;height:100px;"></span>
</div>
<div class="col-sm-4 col-xs-4 col-sm-offset-2 col-xs-offset-2"> <span ng-show="scanSrc"><img src="" id="myScan" style="width:100px;height:100px;"></span>
</div>
</div>
<div class="form-group col-sm-12 col-xs-12">
<div class="btn-group btn-next">
<input class="btn btn-primary btn-lg" type="submit" value="Next">
</div>
</div>
</div>
</form>
on creating android app fields name,fathername are lagging. they are showing the data we are entering after few seconds which is too much.
Since you are not going into very much detail with your question, I cant go into detail with my answer.
Ill try to explain where your issues might come from and adjust my answer if you provide more information:
Cordova uses WebView container in a native App which basicly uses the same engine for rendering as your mobile browser. The performance bottleneck of browsers is accessing of DOM elements (causing reflow and rerendering). Therefore you have to be very aware of the performance issues it can create communicating with DOM api. If Your DOM changes take more than 16 ms to render your application becomes visibly slow and sluggish. Going down from 60 fps your performance issues get more and more obvious to the user.
Since mobile devices are alot slower than desktop computers you will have to be very cautious about alot of things.
There are alot of performance hacks you can apply to your mobile web app.
here are some: https://quickleft.com/blog/4-steps-to-minimizing-rendering-issues-in-cordova-applications/
With ReactJs and overuse of CSS transitions you can achive ~60fps applications that almost seem to be native. I have made good experiences with this.
EDIT1: My Hint:
rebuild your Frontend with ReactJs and avoid overuse of frameworks. Keep your DOM structure clean and do animations with CSS (try to avoid js based animations as much as you can!). Measure your FPS while you develop and find performance issues straight away. To build a nice performant nativelike app you will find no way arround this approach.
I hope this helped.

Hiding error messages using angularjs watchCollection

I have two forms in a separate accordion. The first form is an individual information form and the other one is a company information form. Here is the code:
<div class="col-md-10 col-sm-12 col-md-offset-1">
<section class="basic-info">
<div class="heading text-center">
<h1>Basic Information</h1>
<p>Register as an individual OR as a company</p>
</div>
<div class="separator"></div>
<div class="custom-accordion">
<accordion close-others="oneAtATime">
<accordion-group is-open="status.isFirstOpen">
<accordion-heading>
Individual Information<i class="pull-right" ng-class="{'fa fa-angle-down': status.isFirstOpen, 'fa fa-angle-right': !status.isFirstOpen}"></i>
</accordion-heading>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>First Name</label>
<input type="text" ng-disabled="(user.company_name.length > 0 || user.company_number > 0) && (SignUpForm.company_number.$dirty || SignUpForm.company_name.$dirty) " class="form-control input-md" ng-model="user.first_name" name="first_name" placeholder="First Name" required>
</div>
<div ng-messages="SignUpForm.first_name.$error" ng-if="SignUpForm.first_name.$dirty">
<div ng-message="required">
<span>Please enter first name</span>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Last Name</label>
<input type="text" ng-disabled="(user.company_name.length > 0 || user.company_number > 0) && (SignUpForm.company_number.$dirty || SignUpForm.company_name.$dirty) " class="form-control input-md" ng-model="user.last_name" name="last_name" placeholder="Last Name" required>
</div>
<div ng-messages="SignUpForm.last_name.$error" ng-if="SignUpForm.last_name.$dirty">
<div ng-message="required">
<span>Please enter your last name</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Salutation</label>
<select class="form-control input-md" ng-disabled="(user.company_name.length > 0 || user.company_number > 0) && (SignUpForm.company_number.$dirty || SignUpForm.company_name.$dirty)" ng-model="user.salutation" name="salutation" required>
<option value="">Select Salutation</option>
<option value="Mr">Mr</option>
<option value="Mrs">Mrs</option>
</select>
</div>
<div ng-messages="SignUpForm.salutation.$error" ng-if="SignUpForm.salutation.$dirty">
<div ng-message="required">
<span>Please select a salutation</span>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Middle Name</label>
<input type="text" ng-disabled="(user.company_name.length > 0 || user.company_number > 0) && (SignUpForm.company_number.$dirty || SignUpForm.company_name.$dirty)" class="form-control input-md" ng-model="user.middle_name" name="middle_name" placeholder="Middle Name" required>
</div>
<div ng-messages="SignUpForm.middle_name.$error" ng-if="SignUpForm.middle_name.$dirty">
<div ng-message="required">
<span>Please enter your middle name</span>
</div>
</div>
</div>
</div>
</accordion-group>
<accordion-group is-open="status.open">
<accordion-heading>
Company Information<i class="pull-right" ng-class="{'fa fa-angle-down': status.open, 'fa fa-angle-right': !status.open}"></i>
</accordion-heading>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Company Name</label>
<input type="text" ng-click"check()" class="form-control input-md" ng-model="user.company_name" name="company_name" placeholder="Company Name" required
ng-disabled="(user.first_name.length > 0 || user.last_name.length > 0 || user.middle_name.length > 0 || user.salutation.length > 0) && (SignUpForm.middle_name.$dirty || SignUpForm.first_name.$dirty|| SignUpForm.last_name.$dirty || SignUpForm.salutation.$dirty)">
</div>
<div ng-messages="SignUpForm.company_name.$error" ng-if="SignUpForm.company_name.$dirty">
<div ng-message="required" >
<span>Please enter a company name</span>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label>Company Number</label>
<input type="text" class="form-control input-md" ng-model="user.company_number" name="company_number" placeholder="Company Number" required ng-disabled="(user.first_name.length > 0 || user.last_name.length > 0 || user.middle_name.length > 0 || user.salutation.length > 0) && (SignUpForm.middle_name.$dirty || SignUpForm.first_name.$dirty || SignUpForm.last_name.$dirty || SignUpForm.salutation.$dirty)">
</div>
</div>
<div ng-messages="SignUpForm.company_number.$error" ng-if="SignUpForm.company_number.$dirty">
<div ng-message="required">
<span>Please enter company number</span>
</div>
</div>
</div>
</accordion-group>
</accordion>
</div>
<div class="navigation-btns text-center">
<a ui-sref="form.accountInfo" class="btn btn-info back-btn" ng-click="update(15)">Back</a>
<a ui-sref="form.address" class="btn btn-info continue-btn" ng-click="update(31)">Save and Continue</a>
</div>
<div class="clearfix"></div>
<div class="separator"></div>
</section>
The user should only be able to fill out one of the forms and the other one should be disabled. I am using ngdisabled to accomplish this.
Additionally, I am using $scope.$watchCollection to watch the input fields so that if the user enters a value in at least one of
the input fields of one of the individual information form and then decides to clear
what they have entered and fill out the company information form instead. The error messages that are shown in individual form should have been reset to pristine
based on the following code:
$scope.$watchCollection('[user.company_name,user.company_number,user.first_name,user.last_name,user.middle_name,user.salutation]',function(newValue){
//set individual form inputs to pristine
if(newValue[0].length > 0 || newValue[1] > 0 ){
$scope.SignUpForm.first_name.$setPristine();
$scope.SignUpForm.last_name.$setPristine();
$scope.SignUpForm.middle_name.$setPristine();
$scope.SignUpForm.salutation.$setPristine();
}
//set company form inputs to pristine
if((newValue[2].length > 0) || (newValue[3].length > 0) || (newValue[4].length > 0) || (newValue[5].length > 0)){
$scope.SignUpForm.company_name.$setPristine();
$scope.SignUpForm.company_number.$setPristine();
}});
What I have done so far partially works, the first if conditional statement block within $scope.$watchCollection should set the form
fields of first_name, last_name, middle_name and salutation to pristine if the company name or the company number has a value.
When I enter a value into the company_name input field, any of the input fields that has an error message in the individual form got cleared.
However, if I enter a value into the company_number input field first, none of the error messages got cleared.
The second if statement block does not even work probably either. What could I be doing wrong? Thanks in advance.

Categories

Resources