Angular losing scope in ng-form template - javascript

I am trying this ,
<div ng-form="sadadPaymentForm" class="sadadPaymentForm" ng-if="vm.isSadadEnabled" name="sadadPaymentForm" validate-popup-form>
<div ng-if="vm.isSadadEnabled">
<div class="credit-debit-card-div" ng-include="'sadadTemplate'" ng-show="vm.view_tab == 'tab7'">
</div>
</div>
</div>
<span ng-show="vm.view_tab=='tab7' && vm.isSadadEnabled">
<button type="button" class="primary inline pay-now" id="paynowbtn" ng-disabled="!vm.checked3 || vm.sadadPaymentForm.$invalid" ng-click="vm.payByVoucher();" analytics-on="click" analytics-event="uaevent" analytics-eventcategory="Payment" analytics-eventaction="PayNow"
analytics-eventlabel="Pay now">
Pay by sadad
</button>
</span>
And , my template in another html file
<script type="text/ng-template" id="sadadTemplate">
<input fieldlabel="Online Payment ID" type="text" name="onlinePaymentId" ng-model="vm.sadadpayment.onlinePaymentId" class="form-control input-type-text"
ng-model-options="{ debounce: 100 }" validationKey-required="PaymentAdress1IsRequired" required maxlength="200">
</script>
Here the vm.sadadPaymentForm.$invalid does not work but Indidual components validation works on blur on blur of input .
BUT , if I add vm to ng-form ,ie like this
<div ng-form="vm.sadadPaymentForm" class="sadadPaymentForm" ng-if="vm.isSadadEnabled" name="vm.sadadPaymentForm" validate-popup-form>
<div ng-if="vm.isSadadEnabled">
<div class="credit-debit-card-div" ng-include="'sadadTemplate'" ng-show="vm.view_tab == 'tab7'">
</div>
</div>
</div>
Here the vm.sadadPaymentForm.$invalid works but Indidual components validation fails on blur of input for eg, TypeError: Cannot read property 'onlinePaymentId' of undefined
Help me understand how can I make both individual validation and the final form validation work together.Angular Ver 1.5,cannot upgrade this now.Need a solution with 1.5.

Form name attribute should have sadadPaymentForm inspite of vm.sadadPaymentForm. Since you don't have form name specified correctly, validation is failing.
name="vm.sadadPaymentForm"
should be
name="sadadPaymentForm"

Ok found out the issue , its basically a scope issue.
replaced
ng-if="vm.isSadadEnabled"
with
ng-show="vm.isSadadEnabled"
ng-if was preventing the DOM from rendering thus killing the scope variable vm itself

Related

Angular JS - Notify the user if form is successfully submitted using HTML element

I am new to Angular JS and using it as the framework for my client-side JavaScript. I want to notify the user if the form is successfully submitted using HTML element (not an alert which the user requires to click "OK" in order to continue input). I used ngShow to show the element when the form is submitted. Below is the code of the element.
<p ng-model="successMessage" ng-show="isSuccess"></p>
However, it does not suit me because I am refreshing the page after the user submitted form successfully. As you know, this will cause the variables in $scope refreshed.
$route.reload();
To overcome that, I tried to not refreshing the page. Instead, I emptied all the models on my controller. Yet, it does not work well for me because I am using Angular form validation i.e. !frmRegister.address.$pristine and frmRegister.address.$invalid for all my input. Using these, I am displaying error message if the user has touched the input element, but the input content is still not right. Below is the example.
<div class="form-group row" ng-class="{ 'has-danger' : frmRegister.name.$invalid && !frmRegister.name.$pristine }">
<label class="col-2 col-form-label">Employee Name</label>
<div class="col-10">
<input class="form-control" ng-class="{ 'form-control-danger' : frmRegister.name.$invalid && !frmRegister.name.$pristine }" type="text" placeholder="Enter name..." id="txtName" name="name" ng-model="name" ng-maxlength="50" required autofocus>
<p ng-show="frmRegister.name.$invalid && !frmRegister.name.$pristine" class="form-control-feedback">Name is required.</p>
<p ng-show="frmRegister.name.$error.maxlength" class="form-control-feedback">Name is too long.</p>
</div>
</div>
As I was not refreshing the page and only emptying the model, the error messages are raised due to the input has been touched.
How can I achieve to display a success message on submitted form using Angular? Any help would be appreciated.
If the$route.reload is important, you could also tack on ?success=true or similar to your route before the reload:
...
$route.updateParams({success:"true"});
$route.reload();
...
Inject $routeParams into your controller and check accordingly:
function Controller($scope, $routeParams) {
if($routeParams && !!$routeParams.success){
$scope.showSuccessMessage = true;
}
}
<p> tag don't support ng-model, you have to use ng-bind. and if you successfully changed value of isSuccess, I think it will showup with ng-bind.
refer the below example about ng-model and ng-bind.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app ng-init="data='test';iSuccess=true;">
<h3>Shown nothing by ng-model</h3>
<p ng-model="data" ng-show="iSuccess"></p>
<h3>Shown by ng-bind</h3>
<p ng-bind="data" ng-show="iSuccess"></p>
<button ng-click="iSuccess=!iSuccess">Toggle</button>
</div>
Well, without reloading,
you can clear your form through this code during submit.
$scope.yourFormModel = {};
$scope.yourFormName.$setPristine(true);
$scope.yourFormName.$setUntouched(true);
It will clear your form like it is untouched without refreshing the page.
Also, in your success message, use this code instead
<div ng-show="isSuccess">
{{successMessage}}
</div>

Dynamic form validation using angular 2

I am working on angular 2 application and creating the form fields dynamically(using json) in a subsection template. I wanted to disable submit button when the form is invalid.
<h1>Form Validation</h1>
<div >
<form #loginForm="ngForm">
<subsection [question]="fieldsData"></subsection>
<button type="submit" [disabled]="!loginForm.form.valid">Submit</button>
</form>
</div>
Sub section as it follows
<div *ngFor="let data of question">
<label> {{data.displayName}}</label>
<input type="data.dataType" name="data.fieldId" [(ngModel)]="data.fieldValue" required name="data.fieldId" #name="ngModel">
<div *ngIf="name.errors && (name.dirty || name.touched)" class="alert alert-danger">
<div [hidden]="!name.errors.required">
Name is required
</div>
</div>
<br><br>
I have a requirement where submit button should be enabled after all the required fields are filled
Created plunker link Here
Based on your plunkr I think you'd be better served using a reactive form rather than the template driven form approach you have described, as you are defining your form fields in a model anyway (the fieldsData array defined in AppComponent).
The current template approach isn't giving you the validation behaviour you want as the input fields in the sub-component are not participating in the wider form - if you debug loginForm.value you will see that the name fields are not part of the form - meaning that if you submit the form, the form will not contain the data entered in those fields.
An alternative is to make the sub-component participate in the form by implementing ControlValueAccessor as described here but this adds complexity you may not need.
A simpler way would be (1) use reactive forms or (2) don't use a nested subsection component at all.
<form #loginForm="ngForm">
<div *ngFor="let data of fieldsData">
<label> {{data.displayName}}</label>
<input type="data.dataType" [(ngModel)]="data.fieldValue" required [name]="data.fieldId" #name="ngModel">
<div *ngIf="name.errors && (name.dirty || name.touched)" class="alert alert-danger">
<div [hidden]="!name.errors.required">
{{data.displayName}} is required
</div>
</div>
</div>
<button type="submit" [disabled]="!loginForm.form.valid">Submit</button>
Form contains: {{loginForm.value | json }}
</form>
question.component.html
<form #loginForm="ngForm">
<div *ngFor="let data of question">
<label> {{data.displayName}}</label>
<input type="data.dataType" [(ngModel)]="data.fieldValue" required name="data.fieldId" #name="ngModel">
<div *ngIf="name.errors && (name.dirty || name.touched)" class="alert alert-danger">
<div [hidden]="!name.errors.required">
{{data.displayName}} is required
</div>
</div>
<br><br>
</div>
<button type="submit" [disabled]="loginForm.invalid">Submit</button>
</form>
The above disables the submit button you can use the above to activate using *ngIf. You can also use the above as !loginForm.valid.
app.component.html
<h1>Form Validation</h1>
<subsection [question]="fieldsData"></subsection>

Angular Form Validation: $error.required set even when ng-required=false with custom input directive

I have Custom input component with validation with ngMessages,FormController and ng-required:
<div class="col-sm-9 col-xs-12">
<input
id="{{$ctrl.fieldName}}"
name="{{$ctrl.fieldName}}"
class="form-control"
type="text"
minlength="{{$ctrl.minLength}}"
maxlength="{{$ctrl.maxLength}}"
ng-required="{{$ctrl.isRequired === 'true'}}"
ng-model="$ctrl.value"
ng-change="$ctrl.form.$submitted = false;"
>
<div
ng-messages="$ctrl.form[$ctrl.fieldName].$error"
ng-if="$ctrl.form.$submitted"
>
<span class="help-block" ng-message="required">
Field is required
</span>
<span class="help-block" ng-message="minlength">
Minimum length of field: {{$ctrl.minLength}}
</span>
<span class="help-block" ng-message="maxlength">
Maximum length of field: {{$ctrl.maxLength}}
</span>
</div>
</div>
Which is used in this way:
<act-text-field
form="heroAddForm"
field-name="name"
min-length="3"
max-length="15"
is-required="true"
errors="$ctrl.errors.name"
ng-model="$ctrl.hero.name">
</act-text-field>
What I want to achieve is validation fires when user clicks submit button. And it works, validation fires also for required field name, but also for field description which is not required:
<act-text-field
form="heroAddForm"
field-name="description"
max-length="50"
is-required="false"
errors="$ctrl.errors.description"
ng-model="$ctrl.hero.description"
></act-text-field>
Also for this field validation messages are visible, although field description is valid, cause I add class has-error to invalid fields:
<div class="form-group"
ng-class="{'has-error': $ctrl.form.$submitted && (!$ctrl.form[$ctrl.fieldName].$valid)}"
>
<!-- rest of code -->
You can easily reproduced this wrong behaviour in my Plunker: Custom input demo app with validation states (I know it has other mistakes). I think ng-message="required" should not be visible, because field description is not required. I know I can add some ng-ifs to code to by-pass it, but I think I make a mistake somewhere which I can't see. Do you see where I made a mistake? Thank you in advance for every help.
I found a solution, again I forgot to include ngMessages. Without it, my code went crazy, I apologize for wasting your time :)

validating input fields using angular and jquery?

I’m using angular.js and jQuery to validate user inputs in a form that is created using an ng-repeat. So essentially I have an array of strings(barcodes) I loop through and display, I also display an input field. The user is going to use a barcode scanner, think of it like a copy/paste effect, to enter strings into the input fields. If the barcode doesn’t match the string thats next to it than it should alert the user and clear the input field. I have the code below that uses ng-model-options ‘Blur’ to perform this and it almost works. Right now it alerts the user three times every time an inputs is incorrect. I cannot figure out why it fires three times? there must be a more elegant way of achieving this validation with angular/jQuery? maybe a directive? I’m new with angular so any help is greatly appreciated, Thanks!
HTML:
<div ng-repeat="(index, val) in barcodes.barcodes track by $index">
<div class="form-group row" ng-show="barcodes.barcodes[index]">
<div ng-if="barcodes.barcodes[index] != 'X'">
<label class="col-sm-3 form-control-label" style="margin-top:5px"> {{ barcodes.barcodes[index] }} </label>
<label class="col-sm-2 form-control-label" style="margin-top:5px"> {{ barcodes.A_adaptors[$index+8] }} </label>
<div class="col-sm-1" style="margin-top:5px">
<button class="btn btn-xs btn-default hvr-pop" data-toggle="dropdown" ng-click="getIndex($index+8)"><i class="fa fa-cogs" aria-hidden="true" style="color:#DF3D42"></i></button>
<ul class="dropdown-menu" role="menu">
<div ng-repeat="x in barcodes.B_adaptors">
<li class="text-center" ng-click="replace(x)" id="B_adaptors">{{ x }}</li>
</div>
</ul>
</div>
<div class="col-sm-6">
<input type="text" class="form-control matching" ng-model-options="{ updateOn: 'blur' }" ng-model="item.barcodeInput" placeholder="Barcode" required>
<div ng-show="!isEqualToBarcode($index+8, item.barcodeInput)"> Error: Barcode not the same! </div>
</div>
</div>
</div>
</div>
JAVASCRIPT: (in controller)
$scope.isEqualToBarcode = function(index, val) {
if(val === null || val === undefined) return true;
if($scope.barcodes.A_adaptors[index] !== val.trim()) {
console.log("wrong", val);
alert("Incorrect Barcode, Try Again.");
val = "";
}
return $scope.barcodes.A_adaptors[index] === val.trim();
}
One way is to change it to an angular form.
Angular gives input validation and flags for invalid input.
Here is a link to get you started
You can also define your own validator directives for the same.
https://docs.angularjs.org/guide/forms
It's because ng-show is expecting a boolean, functions don't usually work as expected in ng-show. Try putting the isEqualToBarcode function on the input inside an ng-blur event.
That being said a better solution would be to use angular's input/form validation, i briefly explained how to use it here but you might want to take a look at the documentation or a tutorial if you're completely new to it. The kind of validation you want doesn't come with angular out of the box, luckily other people have already created a custom directive to handle that. It was made for confirming a password but the basic functionality is still the same (matching 2 values). This might seem like the long way around but trust me it will save you a lot of trouble on the long run.

Validation directive code is executed on every item in ng-repeat

I am writing a single page application using Angular and Breeze. I have a set of entities displayed on my page using data-ng-repeat.
I am doing in place validation on the entities by having an "edit mode" div and a "display mode" div that are alternately hidden and shown using data-ng-hide and data-ng-show. One one entity at time can be in edit mode.
In the edit mode div, I have a bunch of inputs bound to the Breeze entity using data-ng-model and I am hooking in the Breeze entity validation using data-z-validate as described in the Breeze labs docs for their Angular validation directive:
http://www.breezejs.com/breeze-labs/breezedirectivesvalidationjs
The HTML looks like this (cut down for clarity):
<div data-ng-controller="payees as vm">
<div data-ng-repeat="payee in vm.payees">
<!--Display mode content-->
<div data-ng-hide="payee.editing">
<span>{{payee.name}}</span>
<span>{{payee.addressLine1}}</span>
<span>{{payee.town}}</span>
<span>{{payee.postcode}}</span>
<!--Some more markup here to switch to edit mode-->
</div>
<!--Edit mode content-->
<div data-ng-show="payee.editing">
<input data-z-validate data-ng-model="payee.name" />
<input data-z-validate data-ng-model="payee.addressLine1" />
<input data-z-validate data-ng-model="payee.town" />
<input data-z-validate data-ng-model="payee.postcode" />
<!--Some more markup here to save changes or cancel edit mode-->
</div>
</div>
</div>
The problem is that each time I type in one of the input, the validate directive code is executed for every input on every item in the repeater - even the ones that are hidden. I can see this by putting a breakpoint in my debugger. When I have lots of entities, surely this will make the responsiveness of the page very bad. In my code example, if I have 100 payees, then the validation code will execute 400 times (one for each of 4 properties on each of 100 payees), when really, it only needs to execute 4 times.
My question is: Is there a way of making the validation happen only for the entity that is currently in edit mode, or equivalently, only for the inputs that are not hidden?
For mutually exclusive conditions (for instance, a ngShow and a ngHide with the same value), you should use the ngSwitch directive, as recommended in the AngularJS FAQ:
Note especially the powerful ng-switch that should be used instead of several mutually exclusive ng-show.
In your case, with ngSwitch and in "display mode", the <input> tags will not exist anymore, and the validation directives will not be executed.
<div data-ng-controller="payees as vm">
<div data-ng-repeat="payee in vm.payees" data-ng-switch="payee.editing">
<!--Display mode content-->
<div data-ng-switch-when="false">
<span>{{payee.name}}</span>
<span>{{payee.addressLine1}}</span>
<span>{{payee.town}}</span>
<span>{{payee.postcode}}</span>
<!--Some more markup here to switch to edit mode-->
</div>
<!--Edit mode content-->
<div data-ng-switch-default>
<input data-z-validate data-ng-model="payee.name" />
<input data-z-validate data-ng-model="payee.addressLine1" />
<input data-z-validate data-ng-model="payee.town" />
<input data-z-validate data-ng-model="payee.postcode" />
<!--Some more markup here to save changes or cancel edit mode-->
</div>
</div>
</div>

Categories