show component error in mat-from-field angular 9 - javascript

i want to create a share component for show error in angular material .
this is my share component pfa-share-error:
<mat-error *ngIf="fieldErrors(fieldName).required && fieldErrors(fieldName)">
Reqierd
</mat-error>
<mat-error *ngIf="fieldErrors(fieldName).touched && fieldErrors(fieldName)">
Reqierd
</mat-error>
<mat-error *ngIf="fieldErrors(fieldName).pattern && fieldErrors(fieldName)">
Reqierd
</mat-error>
and i using this in the my form :
<mat-form-field appearance="outline">
<mat-label>{{ "COUNTEY.NAME" | translate }}</mat-label>
<input formControlName="name" matInput />
<pfa-share-error [form]="addCountryFG" field="name"></pfa-share-error>
</mat-form-field>
but it show like this in my form when error occure :
i want show that like this :
now how can i solve this problem ????

You may try something like following:
In your main HTML file:
<mat-form-field appearance="outline">
<mat-label>{{ "COUNTEY.NAME" | translate }}</mat-label>
<input formControlName="name" matInput />
<mat-error>
<pfa-share-error [form]="addCountryFG" field="name"></pfa-share-error>
</mat-error>
</mat-form-field>
In your shared component pfa-share-error:
<ng-container *ngIf="fieldErrors(fieldName).required && fieldErrors(fieldName)">
This field is required and cannot be empty
</ng-container>

Related

Add dynamic component in the DOM

I have a project in Angular in which I have created a dialog with several fields for a component. What I want is to take advantage of this dialog for other components, but the amount of data varies.
This is my dialog.component.html:
<div class="dialog-container">
<mat-form-field>
<input matInput placeholder="Name" [(ngModel)]="data.name">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Phone" [(ngModel)]="data.phoneNumber">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Email" [(ngModel)]="data.email">
</mat-form-field>
</div>
I want to know if it is possible to create only one mat-form component and display as many as necessary, passing it the number of fields that I want to generate.
This is what I want the dialog.component.html to contain, to achieve the same as above (I don't know if this is possible):
<div class="dialog-container">
<mat-form-field>
<input matInput placeholder={{place}} [(ngModel)]={{data}}>
</mat-form-field>
</div>
From only one mat-form-field is it possible to show the same result as the first example?
You could create a custom directive :
import { Directive, Input } from '#angular/core';
import { NgForOf } from '#angular/common';
#Directive({
selector: '[ngFor][ngForRepeat]'
})
export class NgForRepeat<T> extends NgForOf<T> {
#Input() set ngForRepeat(repeat: number) {
this.ngForOf = new Array(repeat >= 0 ? repeat : 0);
}
}
And use it as follow in you template :
<ng-container *ngForRepeat="3">
<mat-form-field>
<input matInput placeholder={{place}} [(ngModel)]={{data}}>
</mat-form-field>
</ng-container>

mat-autocomplete the option value does not appear correctly in IOS device

When I select the first option in the dropdown, the option is not reflected in the field. When I select the second option then first option value appears and when selects third the second option value appears. Any suggestions as to what the problem is in my code?
This is happening only on iOS devices.Its working fine on Android and Desktop.
emailDomains = AvailableDomains.emailDomains;
export const AvailableDomains = {
emailDomains: [
"hotmail.com",
"gmail.com",
"yahoo.com",
"outlook.com"
]
}
<mat-form-field appearance="outline" class="textbox mat-form-field-invalid">
<span class="iconError icon-alert" aria-hidden="false" aria-label="Error"></span>
<mat-label>Email</mat-label>
<input matInput placeholder="Enter" formControlName="email" type="email" [matAutocomplete]="emailAutoComplete" #email>
<mat-autocomplete #emailAutoComplete="matAutocomplete" panelWidth="auto">
<mat-option *ngFor="let emailDomain of (email.value.endsWith('#') && email.value.split('#').length == 2 ? emailDomains : [])" [value]="email.value + emailDomain">#{{emailDomain}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
I have some auto-complete code that does work on IOS. I compared the two and the difference I see is that I am using (optionSelected) on the mat-autocomplete tag instead of (onSelectionChange) on the mat-option tag. Try it and see.
<mat-form-field appearance="outline" class="textbox mat-form-field-invalid">
<span class="iconError icon-alert" aria-hidden="false" aria-label="Error"></span>
<mat-label>Email</mat-label>
<input matInput placeholder="Enter" formControlName="email" type="email" [matAutocomplete]="emailAutoComplete" #email>
<mat-autocomplete #emailAutoComplete="matAutocomplete" panelWidth="auto" (optionSelected)="updateForm($event,emailDomain)">
<mat-option *ngFor="let emailDomain of (email.value.endsWith('#') && email.value.split('#').length == 2 ? emailDomains : [])" [value]="email.value + emailDomain">#{{emailDomain}}
</mat-option>
</mat-autocomplete>
</mat-form-field>

value of formControl not displayed on view

I have a form with many fields, It was made with formGroup and formControlName.
The problem is when I start the app I need to get the data from the backEnd and display it on the view.
The problem is that the field Funcion is not displaying the value:
Here is a reduced part of my html code:
<form #f="ngForm" [formGroup]="registros" class="fila-contenido">
<div class="campos">
<!-- En Venta THIS IS OK-->
<label>¿En venta?</label>
<mat-radio-group formControlName="enVenta" aria-labelledby="example-radio-group-label"
class="example-radio-group">
<mat-radio-button value="1" class="example-radio-button">Si</mat-radio-button>
<mat-radio-button value="0" class="example-radio-button">No</mat-radio-button>
</mat-radio-group>
</div>
<!-- Activo THIS IS OK-->
<div class="campos">
<label>¿Registrado?</label>
<mat-radio-group formControlName="activo" aria-labelledby="example-radio-group-label"
class="example-radio-group">
<mat-radio-button value="Si" class="example-radio-button">Si</mat-radio-button>
<mat-radio-button value="En Trámite" class="example-radio-button">En Trámite</mat-radio-button>
<mat-radio-button value="No Necesita" class="example-radio-button">No Necesita
</mat-radio-button>
<mat-radio-button value="No" class="example-radio-button">No</mat-radio-button>
</mat-radio-group>
</div>
<!-- Pais THIS IS OK-->
<mat-form-field appearance="">
<mat-label>Pais</mat-label>
<mat-select formControlName="pais">
<mat-option *ngFor="let pais of selectedPaises" [value]="pais">{{pais}}</mat-option>
</mat-select>
</mat-form-field>
<!-- Funcion THIS IS NOT OK-->
<mat-form-field appearance="">
<mat-label style=" font-weight: bold;">Función</mat-label>
<mat-select formControlName="funcion" required (selectionChange)=changeFuncion($event)>
<mat-option *ngFor="let funcion of funciones" [value]="funcion">{{funcion.Funcion}}
</mat-option>
</mat-select>
</mat-form-field>
</form>
And here is the TS code:
ngOnInit(): void {
this.getRegistros();
}
getRegistros() {
this.http.get<Registro>('http://localhost:7000/api/registros/' + this.service.getRow()).subscribe(data => {
data.log = data.log.replace(/\\"/g, '"');
console.log("formateo", JSON.parse(data.log));
let convert = JSON.parse(data.log);
this.registros.controls.enVenta.setValue(convert.enVenta); //this is OK
this.registros.controls.activo.setValue(convert.activo); //this is OK
this.registros.controls.pais.setValue(convert.pais); //this is OK
this.registros.controls.funcion.setValue(convert.funcion); //this is not OK
});
}
What I've tried:
I've a write a console.log with all the values of the form, the form has all values included the one that is not displayed.
I think it can be related to the ngOnInit problem. But I tried to put getRegistros() on ngAfterViewInit and I was having the same problem :(
Also I tried to use patchValue() instead of setValue() but same problem
Do you have any suggestions?
Thanks.
Angular uses object identity to select option. It's possible for the
identities of items to change while the data does not. This can
happen, for example, if the items are produced from an RPC to the
server, and that RPC is re-run. Even if the data hasn't changed, the
second response will produce objects with different identities.
To overcome this issue we have to provide the compareFn function to mat-select using compareWith input that tells Angular how to compare the values.
Try this:
component.html
<mat-form-field appearance="">
<mat-label style=" font-weight: bold;">Función</mat-label>
<mat-select formControlName="funcion" required (selectionChange)=changeFuncion($event) [compareWith]="compareWithFn">
<mat-option *ngFor="let funcion of funciones" [value]="funcion">{{funcion.Funcion}}
</mat-option>
</mat-select>
</mat-form-field>
component.ts
Here i am assuming your funciones object contains id property.
compareWithFn(listOfItems,selectedItem){
return listOfItems && selectedItem && listOfItems.id === selectedItem.id; ;
}
I think issue is in your template file:
Updated Template:
<mat-form-field appearance="">
<mat-label style=" font-weight: bold;">Función</mat-label>
<mat-select formControlName="funcion" required (selectionChange)=changeFuncion(funcion) [(ngModel)]="funcion">
<mat-option *ngFor="let funcion of funciones" [value]="funcion">{{funcion.Funcion}}
</mat-option>
</mat-select>
</mat-form-field>
Component:
funcion:any;

Angular: is it possible in the result of method in ngIf reuse in yours child item?

I have a problem, is it possible put inside on an element the result of method call in template?
controlError(item.name) method return if there is an error a string with the error else return null
<table class="w-100">
<td *ngFor="let item of form.fields">
<mat-form-field class="w-100" *ngIf="item.dataType==='string'">
<mat-label>{{ item.labelDefault | translate}}</mat-label>
<input type="text" matInput required formControlName="{{item.name}}">
<mat-error *ngIf="controlError(item.name)">
//result of controlError
</mat-error>
</mat-form-field>
</td>
</table>
if is it possible how to resolve him?
Try the as construct of the *ngIf directive.
<mat-error *ngIf="(controlError(item.name)) as result">
{{ result }}
</mat-error>

Setting angular material date picker value programmatically

I am using angular material date picker in one of my component's of angular project. This component has two tabs. Using *ngIf I am showing only one at a time based on what user has clicked.In one tab user selects a date and if navigate away to other tab of same component and comes back to previous one, I need to retain the selected date.
This is what I am doing in HTML side:
<mat-form-field class="dropdownWidth">
<input #dateInput matInput [matDatepickerFilter]="myFilter" [matDatepicker]="picker"
placeholder="Choose a date"
[value]="datePickerDate"
[(ngModel)]="datePickerDate"
(dateChange)="addDateEvent($event)"
[disabled]="selectedOperator.length === 0 && userDateRange.length === 0">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
And in TS file:
addDateEvent(event) {
this.datePickerEvent = event;
this.datePickerDate = new Date(`${event.value['_i'].month + 1}-${event.value['_i'].date}-${event.value['_i'].year}`);
this.formatDate = moment(event.value).format('YYYY-MM-DD');
}
But when I navigate back, date value is not retained. Any suggestions how can I achieve this?
Here is sample stackblitz
It does not work because you are not storing a selected value. So create a variable in typescript:
yourDate: any;
HTML:
<p> YourDate {{ yourDate | date }} </p>
<mat-form-field>
<input matInput [(ngModel)]="yourDate" [matDatepicker]="picker" placeholder="Choose a date">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
It is possible to see the whole code at stackblitz
In your example you are not using any bindings. Try to use [(ngModel)], so that it will take and hold the selected value.
Do like this, it will work:
<mat-form-field>
<input matInput [(ngModel)]="date" [matDatepicker]="picker" placeholder="Choose a date">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>

Categories