Error: Cannot change `multiple` mode of select after initialization - html

Error image:
<div fxFlex.gt-lg="100" fxFlex="100" *ngIf="requestAction == 'add'">
<div class="pb-1">
<md2-select placeholder="{{'WidgetType'|translate:lang}}" class="input_custom_width"(change)="widgetNode($event.value)" required>
<md2-option *ngFor="let widgetType of widgetTypeAry" [value]="widgetType.value">
{{widgetType.name}}
</md2-option>
</md2-select>
</div>
</div>
<div fxFlex.gt-lg="100" fxFlex="100" *ngIf="fieldsObj['node'] && showRequestAction" >
<div class="pb-1">
<md2-select placeholder="{{'Node'|translate:lang}}" [formControl]="editWidgetForm.controls['nodeId']" [(ngModel)]="nodeId" class="input_custom_width" [(multiple)]="isMultiNode" (change)="nodeChange($event.value)" required>
<md2-select-header>
<md-input-container class="input_custom_width">
<input mdInput type="text" placeholder="{{'Search'| translate:lang}}" [ngModelOptions]="{standalone: true}" [(ngModel)]="searchNode"/>
</md-input-container>
</md2-select-header>
<md2-option *ngFor="let node of nodesAry | filterPipe : searchNode" [value]="node.value">
{{ node.name }}
</md2-option>
</md2-select>
<small *ngIf="editWidgetForm.controls['nodeId'].hasError('required') && editWidgetForm.controls['nodeId'].touched" class="mat-text-warn">{{'nodeReq'|translate:lang}}</small>
</div>
</div>
When I use multiple in select dropdown it works fine but when I use [multiple] it only works in my edit form but not in add form .and it gives above error-Error: Cannot change multiple mode of select after initialization.help me to sort out this.

There is a very ugly workaround for this problem, warp your mat-select in a *ngif=true, and create a duplicate with the multiple property, wrapped in a *ngif=!true just beneath it

Related

How to prevent repetition in Angular html?

I have an input in my html as follows:
<ng-container *ngIf="({required: <some_condition>, invalid: <some_condition>}) as emailErrors">
<input type="email" class="form-control" placeholder="Email" validate-onblur [class.is-invalid]="emailErrors.required || emailErrors.invalid" [attr.aria-invalid]="emailErrors.required || emailErrors.invalid" [attr.aria-describedby]="emailErrors.required || emailErrors.invalid ? 'email-error' : undefined">
<div *ngIf="emailErrors.required" id="email-error">
<p class="error-msg">{{messages.EMAIL_REQ}}</p>
</div>
</ng-container>
Here in my <input> tag I'm repeting this condition 3 times: emailErrors.required || emailErrors.invalid.
Can I store this condition here in a variable, so that I do not have to repeat it?
P.S. I'm new in Angular
I would recommend you to use the template form of Angular. These are fairly simpler to implement.
In the code below make sure you give name property on the input field otherwise an error will be thrown, while working on with [(ngModel)]
<form #f="ngForm">
<input type="email" class="form-control" placeholder="Email" name="mail" required [(ngModel)]="model.email" #mail="ngModel">
<span *ngIf="mail.invalid">
{{messages.EMAIL_REQ}}
</span>
</form>
Why not introduce an additional property in the wrapping <ng-container>? And seeing that emailErrors.invalid isn't used anywhere else, it could be removed if it's unneeded.
<ng-container *ngIf="({required: <condition_1>, reqOrInv: <condition_1> || <condition_2>}) as emailErrors">
<input
type="email"
class="form-control"
placeholder="Email"
validate-onblur
[class.is-invalid]="emailErrors.reqOrInv"
[attr.aria-invalid]="emailErrors.reqOrInv"
[attr.aria-describedby]="emailErrors.reqOrInv ? 'email-error' : undefined"
>
<div *ngIf="emailErrors.required" id="email-error">
<p class="error-msg">{{messages.EMAIL_REQ}}</p>
</div>
</ng-container>
But as #YashwardhanPauranik noted in their answer, you're better off using Angular template driven or reactive forms. They provide more granular control.

Having trouble with validation error messages in Angular

I am having trouble with error messages in my validation. I want to be able to differentiate between the different errors with different messages. How can I fix this. Here is my typescript function:
createFormControl(){
this.updatedArray.forEach((element: any) => {
element.maxlength = +element.maxlength
if(element.required === "true"){
this.xmlForm.addControl(element.name, new FormControl('',[Validators.required, Validators.maxLength(element.maxlength)]));
}else{
this.xmlForm.addControl(element.name, new FormControl(''));
}
});
console.log(this.xmlForm)
}
Here is and example of a part of my HTML:
<div class="row pb-2" [formGroup]="xmlForm">
<div class="col-lg-4" *ngFor="let form of updatedArray">
<div class="form-group" [ngSwitch]="form.type">
<div *ngSwitchCase="'string'">
<label _ngcontent-emf-c46="" for="input1">{{form.name}}</label>
<input _ngcontent-emf-c46="" type="text" [formControlName]="form.name" placeholder="" id="input1" aria-describedby="Text field"
name="name" class="form-control ng-untouched ng-pristine ng-valid" ng-reflect-name="name"
ng-reflect-model="">
<div *ngIf="xmlForm.get(form.name).dirty || xmlForm.get(form.name).touched">
<small class="error" *ngIf="!xmlForm.get(form.name).valid">
{{form.name}} is Required
</small>
</div>
<div *ngIf="xmlForm.get(form.name).dirty">
<small class="error" *ngIf="!xmlForm.get(form.name).valid">
Max Length is {{form.maxlength}}
</small>
</div>
</div>
Both error messages are popping up when one or the other is true. I just want one showing up. How can I fix this?
Instead of *ngIf="!xmlForm.get(form.name).valid" to check for max length compliance, you should try *ngIf="xmlForm.get(form.name).errors?.maxlength". According to the Angular API, the maxlength property becomes available in the errors map if the specified max length is exceeded. You can do a similar check for required using *ngIf="xmlForm.get(form.name).errors?.required"

required field validation only for the first item in a list

I am using Template Driven for my Angula'rs form and I have a div that repeats several times (according to a counter variable).
The thing is , I need the required validation only for the first item in this list and I 'm not sure how to do that.
<div class="form-group required margin-left" *ngFor="let hore of horim;let i = index">
<label class="control-label translate-label" [id]="'lblShemPratiHore'+i">{{selectedLanguage.shemPrati}}</label>
<!-- <img src="../../../assets/images/parent.png" alt="shem prati"> -->
<input
[id]="'shemPratiHore'+i"
[(ngModel)]="hore.shemPrati"
class="form-control input-lg"
[name]="'shemPratiHore'+i"
[attr.aria-describedby]="'lblShemPratiHore'+i"
#shemPrati="ngModel"
required
[ngModelOptions]="{ updateOn: 'blur' }"/>/>
<div *ngIf="shemPrati.errors?.required && shemPrati.touched" class="alert alert-danger">
Required Field
</div>
</div>
try binding to the required attribute if index is equal 0.
[required]="index == 0"
The anwer for this post is as follow:
[required]="i==0"

Angular 8 Material mat-error shows up on load by default

I am having this weird scenario. my mat-error shows up by default, without even touching the input field. Basically, when I load the page the error message is shown without any user interaction on the input field. I don't have any error messages on the browser console. Can anyone point out what did I miss?
This is my .ts
frmStep3: FormGroup;
matcher = new MyErrorStateMatcher();
// omited unrelated code
this.frmStep3 = this.fb.group({
courseDurationNum: [, [Validators.required, Validators.maxLength(3), Validators.minLength(1)]]
});
return {
frmStep3: this.frmStep3
};
This is my HTML
<form class="form-group-parent p-0" [formGroup]="frmStep3" (ngSubmit)="stepForward()">
<div class="form-group d-inline-block">
<label class="w-100">Choose your course duration<sup>*</sup></label>
<input [errorStateMatcher]="matcher" [maxLength]="3" type="text" class="float-left" matInput
formControlName="courseDurationNum" placeholder="Ex. 1 - 365 Day(s)" />
<mat-error class="w-100 float-left"
*ngIf="frmStep3.get('courseDurationNum').hasError('required') || frmStep3.get('courseDurationNum').invalid">
<strong>Duration</strong> must be between <strong>1 - 365</strong> day(s).
</mat-error>
</div>
</form>
I figured out, I missed wrapping them in from controls in <mat-form-field> tag. Correct code below.
<form class="form-group-parent p-0" [formGroup]="frmStep3" (ngSubmit)="stepForward()">
<div class="form-group d-inline-block">
<mat-form-field>
<label class="w-100">Choose your course duration<sup>*</sup></label>
<input [errorStateMatcher]="matcher" [maxLength]="3" type="text" class="float-left" matInput
formControlName="courseDurationNum" placeholder="Ex. 1 - 365 Day(s)" />
<mat-error class="w-100 float-left"
*ngIf="frmStep3.get('courseDurationNum').hasError('required') || frmStep3.get('courseDurationNum').invalid">
<strong>Duration</strong> must be between <strong>1 - 365</strong> day(s).
</mat-error>
</mat-form-field>
</div>
</form>

required attribute not working with primeng <p-dropdown>

I am working on a angular2 App and I am using primeng for UI elements. I have dropdowns where I am using the options in these dropdowns are dynamically generated from an API call. Now, when I click the submit button, I want it to validate the forms before submitting. So I am using 'required="required"' in order to make the validation happen.
I see that, if the data is not loaded into the dropdowns, the validation works fine, but when the data is loaded and dropdown options are populated, the primeng validation breaks and it does not throw any message.
Here's my html code..
<div method="post" class="content-form">
<div class="col-lg-6">
<form #myForm="ngForm" class="form-horizontal" novalidate>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">System of Origin</label>
<div class="col-sm-10">
<p-dropdown class="contentDetails" [options]="systemOfOrigins" [(ngModel)]="defaultSoO" [ngModelOptions]="{standalone: true}" required="required" filter="filter" placeholder="NONE"></p-dropdown>
</div>
</div>
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label">Content Type</label>
<div class="col-sm-10">
<p-dropdown class="contentDetails" [options]="contentTypes" [(ngModel)]="selectedContentType" [ngModelOptions]="{standalone: true}" filter="filter" required="required" placeholder="Choose"></p-dropdown>
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label">Rendition</label>
<div class="col-sm-10">
<p-dropdown id ="rendition" placeholder="Select Rendition" class="contentDetails" [options]="renditions" [(ngModel)]="renditionSelected" [ngModelOptions]="{standalone: true}" filter="filter" required="required"></p-dropdown>
</div>
</div>
</form>
Am I not using the required attribute properly or is there any other way to do it with API calls ?
Help is appreciated
This issue happens if there is a dummy first element in the options array that is used to display please select text, and the label in that dummy element is having some value in it. So just set the label value as '' or null or undefined. It will work.
Try
<p-dropdown [required]="true">
required is a boolean property. If you are setting it dynamically, [required]="isRequired", otherwise required="true" should do it for you.
Try replacing required="required" with required="true" and seeing if that makes them required. If not, I suggest adding a plunkr