md-autocomplete "required" validation not applied to parent form - angular-material

Following the provided documentation in angular material, I have setup a working autocomplete directive.
The required validation is being shown in the nested error message "div", but there is no effect on the parent form.
The parent form seems to be valid even for empty value in autocomplete.
<form ng-submit="ngSubmit()" layout="column" class="md-padding"
name="itemsForm" flex>
<md-input-container>
<label>Code *</label>
<input type="text" name="code" required ng-model="ngModel.code"/>
</md-input-container>
<md-autocomplete flex
required
md-input-name="author"
md-search-text="searchText"
md-search-text-change="ngModel.author = (searchText)"
md-selected-item-change="ngModel.author = item"
md-items="item in filterAutocomplete(searchText)"
md-item-text="item"
md-floating-label="Author *">
<md-item-template>
<span md-highlight-text="ctrl.searchText">{{item}}</span>
</md-item-template>
<div ng-messages="autocompleteForm.autocomplete.$error">
<div ng-message="required">This field is required</div>
</div>
</md-autocomplete>
<md-button class="md-primary" type="submit"
ng-disabled="itemsForm.$invalid"
ng-class="{'md-raised': itemsForm}">
Save
</md-button>
</form>
How can I achieve the similar behaviour to normal required input fields in side a form, when using md-autocomplete?

There have been some commits in the past few days that address this issue. It is fixed in master I believe.
https://github.com/angular/material/issues/7350
https://github.com/angular/material/issues/5896
You can try this version:
https://cdn.gitcdn.link/cdn/angular/bower-material/v1.0.6-master-3310aa9/angular-material.css
https://cdn.gitcdn.link/cdn/angular/bower-material/v1.0.6-master-3310aa9/angular-material.js

Related

ngxScrollToFirstInvalid is not working which need to scroll the page to error filed?

I'm new to Angular and now I'm working on small task that required scroll to the error field which is not filled while submitted.
I'm getting error at formGroup if I added ngxScrollToFirstInvalid which is working fine in my past projects. Below are my project snippet. I have imported properly in module.ts
<form [formGroup]="myForm" #companyForm="ngForm" novalidate method="POST" autocomplete="off" style="margin-top: 5%" ngx ngxScrollToFirstInvalid>
<div class="candScroll">
<div class="row">
<div class="col-lg col-md col-sm">
<mat-form-field class="size" appearance="outline">
<!-- <mat-label for="company">Company</mat-label> -->
<label class="required">Company</label>
<input matInput formControlName="company" type="text"
[ngClass]="{ 'is-invalid': sub && f['company'].errors }" />
<mat-error *ngIf="sub && f['company'].invalid || f['company'].touched">
<div *ngIf="sub && f['company'].errors" class="invalid-feedback"> company name is required</div>
<span class="text-danger">Please input Company Name</span>
</mat-error>
</mat-form-field>
</div>
...
I tried all steps from https://www.npmjs.com/package/#ismaestro/ngx-scroll-to-first-invalid🔗. And I need to get scroll the page to the error field while submitted (on clicked) if user had not filled the field.

How to validate Form only on submit in Angular Dart?

I am using the Angular Component library which includes material-input. Is there a way to disable input auto validate when changing or emptying the material-input? Meaning that I want to only validate the form upon submit.
Plus the onSignInPressed() function is not getting triggered on submit despite that the material-button is of type submit.
<div class="container">
<form (ngSubmit)="onSignInPressed()" #signInForm="ngForm">
<div>
<material-input
floatingLabel type="email"
label="E-mail"
[(ngModel)]="email"
ngControl="email"
required></material-input>
</div>
<div>
<material-input
floatingLabel type="password"
label="Password"
[(ngModel)]="password"
ngControl="pass"
required></material-input>
</div>
<div class="w-100">
<material-button class="mx-0 btn-primary w-100 margin-zero" type="submit"
[disabled]="!signInForm.form.valid">
Sign In
</material-button>
</div>
</form>
</div>
You can try to use a different value accessor on the material-input, however you won't be able to validate the form on submit.
With changeUpdate, validation will be triggered on blur or when press ENTER
<material-input changeUpdate [(ngModel)]="value"
Docs
About the material-button, there is an issue on github with a hacky solution.
You can also try to add an hidden input
<input type="submit" hidden />

ngMessages and Nested Scopes - Datepicker in an ngForm on a Tab

OP Update
I've figured out the problem and this issue is now closed. Would one day like to find the time to post the solution as an answer here.
I'm having a bit of an issue working with ngMessages inside an ng-form on an Angular Bootstrap tab. Further complicating things, the thing I am validating is a Angular Bootstrap datepicker. So the code is as follows, and as you can see, I've got a datepicker on an ng-form which is on a Tab.
<uib-tab index="5" heading="{{tabs[5].title}}" select="changeCheck($event)">
<ng-form name="{{tabs[5].form}}">
<div class="col-md-9">
...
<div class="col-md-6">
<h4>Add Followup</h4>
<div class="form-group">
<label for="addFollowupDate" class="control-label">Date:</label>
<div class="input-group">
<input type="text" id="addFollowupDate"
class="form-control"
uib-datepicker-popup="{{format}}"
ng-required="true"
ng-model="newFollowup.date"
is-open="addFollowupPopup.opened"
datepicker-options="dateOptions"
close-text="Close"
alt-input-formats="altInputFormats" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="openAddFollowupPopup()"><i class="fa fa-calendar"></i></button>
</span>
<div class="help-block" ng-messages="followupsForm.newFollowup.date.$error" ng-if="followupsForm.newFollowup.date.$invalid && followupsForm.newFollowup.date.$touched">
<div ng-message="required">This field is required</div>
</div>
</div>
</div>
I've assigned that form to the scope using the following line:
$scope.followupsForm = $('ng-form[name="followupsForm"]').data('$formController');
And I have successfully set the control to touched on a submit which does make the border go red:
if ($scope.followupsForm.$invalid) {
angular.forEach($scope.followupsForm.$error, function (formErrorField) {
angular.forEach(formErrorField, function (errorField) {
errorField.$setTouched(); // by setting to touched, the relevant message will display if the field is invalid.
});
});
}
But the ng-message for required does not display.
Any ideas why? Could be a tough one with nested scopes etc. (of the tab and the picker).

Angular material select element not aligned with other form controls

While designing a form using Angular Material I noticed that the <md-select> directive is not aligned with the other input controls. See below:
I literally copied the code from the example on the Angular Material page, and added the <md-select>. Here is my code:
<div layout="column" layout-padding>
<md-content>
<form>
<div layout layout-sm="column">
<md-select placeholder="Title" ng-model="vm.title">
<md-option value="Mr">Mr.</md-option>
<md-option value="Mrs">Mrs.</md-option>
<md-option value="Ms">Ms.</md-option>
</md-select>
<md-input-container flex>
<label>Last Name</label>
<input ng-model="vm.lastName">
</md-input-container>
<md-input-container flex>
<label>First name</label>
<input ng-model="vm.firstName">
</md-input-container>
</div>
<md-input-container flex>
<label>Address</label>
<input ng-model="vm.address">
</md-input-container>
</form>
</md-content>
I tried adding an <md-input-container> with no luck.
My mistake, I discovered this post on GitHub straight after posting: apparently it has already been fixed in the one of the latest commits to master.

Why am I getting this Javascript HIERARCHY_REQUEST_ERR with jQuery Mobile and Razor?

Dazed and confused here... The field in question is a boolean, and I want the UI to be a checkbox (or a yes/no or on/off jQuery slider). Each time I try to add in this checkbox input, I end up getting a
Microsoft JScript runtime error: DOM Exception: HIERARCHY_REQUEST_ERR (3)
error.
Here's the HTML+Razor
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>End Game:</legend>
#Html.TextBoxFor(model => model.HandicapSession.WinByTwo, new { #type="checkbox" })
<label for="WinByTwo">Win By Two?</label>
</fieldset>
</div>
Here's the generated HTML:
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>End Game:</legend>
<input data-val="true" data-val-required="The WinByTwo field is required." id="HandicapSession_WinByTwo" name="HandicapSession.WinByTwo" type="checkbox" value="False" />
<label for="WinByTwo">Win By Two?</label>
</fieldset>
</div>
Apparently this error occurs when there are conflicting or overlapping id's as jQuery Mobile creates its checkbox widget
$.widget( "mobile.checkboxradio", $.mobile.widget, { ...etc...
But how do I use the HTML and/or razor to make a simple checkbox work in jQuery Mobile?
If the problem with jQuery Mobile really is duplicate names for the HTML tags, then you'll have to render your own input type=checkbox tag in HTML, as the ASP.NET MVC Html.CheckBoxFor helper method will render an input type=hidden tag with a duplicate name value. See this post for a discussion.
The hidden form tag is there because if you submit an unchecked checkbox to the server, the form value for that field isn't included. So a hidden input tag is included with value=false so that if the checkbox is unchecked, the value false is still submitted. The model binding process in MVC will filter out the duplicate form values for you, but if you're having a client-side problem with the duplicate name attributes, you'll have to render your own checkbox and label in HTML, then handle the fact that no value will be submitted for the HandicapSession.WinByTwo property when the box is unchecked. If no other property for HandicapSession is submitted, then that whole object will be null.
So, you can manually create the checkbox input and still load the checked and value attributes from your model, as desired, but you can run into model binding problems where the value for WinByTwo will still be false even when the box is checked.
Note also that the for attribute on your label doesn't match the ID of the checkbox in your sample. You need the full HandicapSession_WinByTwo.
The following manually creates the input tags:
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.css" />
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script>
<div data-role="page">
<div data-role="content">
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>End Game:</legend>
<input type="checkbox" id="HandicapSession_WinByTwo" name="HandicapSession.WinByTwo" #(Model.HandicapSession.WinByTwo ? "checked=checked" : "") value="#(Model.HandicapSession.WinByTwo.ToString().ToLower())" />
<label for="HandicapSession_WinByTwo">Win By Two?</label>
</fieldset>
</div>
</div>
</div>
The HTML output is as follows for a checked checkbox on load:
<div data-role="page">
<div data-role="content">
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>End Game:</legend>
<input type="checkbox" id="HandicapSession_WinByTwo" name="HandicapSession.WinByTwo" checked=checked value="true" />
<label for="HandicapSession_WinByTwo">Win By Two?</label>
</fieldset>
</div>
</div>
</div>
The best would be just to use the MVC helper methods, so I'm not sure if you'd tried the following. The default Html.CheckBoxFor and Html.LabelFor helper methods work with jQuery Mobile 1.0a4.1 or 1.1.0 just fine. The following works for me:
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.css" />
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0a4.1/jquery.mobile-1.0a4.1.min.js"></script>
<div data-role="page">
<div data-role="content">
#using (Html.BeginForm())
{
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>End Game:</legend>
#Html.CheckBoxFor(m => m.HandicapSession.WinByTwo)
#Html.LabelFor(m => m.HandicapSession.WinByTwo, "Win By Two?")
<input type="submit" id="SubmitForm" value="submit" />
</fieldset>
</div>
}
</div>
</div>
This produces the HTML output:
<div data-role="page">
<div data-role="content">
<form action="/Mobile/Mobile" method="post">
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>End Game:</legend>
<input checked="checked" data-val="true" data-val-required="The WinByTwo field is required." id="HandicapSession_WinByTwo" name="HandicapSession.WinByTwo" type="checkbox" value="true" />
<input name="HandicapSession.WinByTwo" type="hidden" value="false" />
<label for="HandicapSession_WinByTwo">Win By Two?</label>
<input type="submit" id="SubmitForm" value="submit" />
</fieldset>
</div>
</form>
</div>
</div>
Fix might be pretty simple.
Choice 1: Go scorched earth and turn off Ajax based navigation. This will ensure that unique IDs stay unique. This will ensure that you never encounter this issue again. Only downside is that you lose the pretty little transitions from page to page (someone call the whambulance). You can do this by setting up a global configuration script...
script src="jquery.js"
script src="custom-scripting.js"
script src="jquery-mobile.js"
inside that you'll override the ajax settings to disable them...
$(document).bind("mobileinit", function(){
$.mobile.ajaxEnabled = false;
});
Choice 2: Call pages that are going to require this uniqueness with a link that has an attribute of rel='external' or target='_black' which will accomplish the same thing without disabling all ajax based navigation. If you are reaching the page as a results of a form post, you can use data-ajax='false' on the form tag to accomplish a clean load.

Resources