Angular form validation with select and textarea doesn't work - html

I'm trying creating form validation based on built-in validators, it doesn't work correctly. Form is created with select and textarea controls. The form tag include ngNativeValidate, to disable default novalidate attribute. State is change correctly, so validators works, but I do not have information under controls and form can be subbmitted. It is possible to make validation by disable submit button, but I want to avoid this solution.
HTML:
<form [formGroup]="form" ngNativeValidate (ngSubmit)="addNewJoke()">
<div>
<div>
<select formControlName="category" class="customSelect">
<option value="" disabled hidden>Wybierz kategorię</option>
<option
*ngFor="let category of jokesFacadeService.categories$ | async"
[value]="category.id"
>
{{ category.name }}
</option>
</select>
</div>
<div class="textarea-wrapper">
<textarea
type="text"
class="textarea"
formControlName="content"
placeholder="Wprowadź tekst żartu"
></textarea>
</div>
</div>
<mat-dialog-actions class="modalButton">
<button mat-button mat-dialog-close class="btn-secondary">Anuluj</button>
<button
type="submit"
mat-button
[mat-dialog-close]="true"
class="btn-primary"
>
Dodaj
</button>
</mat-dialog-actions>
</form>
TS:
ngOnInit(): void {
this.form = this.fb.group({
category: new FormControl('', Validators.required,),
content: new FormControl('', [Validators.required,Validators.minLength(3)]),
});
}
I try to change controls to input mark, but this not change anything, the behavior is the same.

Related

HTML & Angular Material disable save button from outside div when form fields are empty

I have the following Angular Material form with the Close and Save buttons in an outside div for design reasons:
<h1 mat-dialog-title>Product Page</h1>
<div mat-dialog-content>
<form [formGroup]="productForm">
<mat-form-field appearance="outline">
<mat-label>Name</mat-label>
<input formControlName="name" required matInput placeholder="Name" style="text-transform:uppercase">
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Weight</mat-label>
<input type="number" required formControlName="weight" matInput placeholder="weight">
</mat-form-field>
</form>
</div>
<div mat-dialog-actions [align]="'end'">
<button mat-raised-button color="warn" mat-dialog-close>Close</button>
<button mat-raised-button color="primary" (click)="saveProduct()">Save</button>
</div>
I want to disable the Save button when the form fields are empty but the required parameter isn't working since the buttons are in an outside div. Is there a way to correlate the buttons with the form such that the Save button is disabled until the required fields are filled in?
You can bind it manually :
<button (click)="submit()" [disabled]="!form.valid">Submit</button>
Or you can cheat your way in the modal by providing the form as the main container (yes, it works)
<form [formGroup]="form">
<h1 mat-dialog-title>...</h1>
<div mat-dialog-content>...</div>
<div mat-dialog-actions align="end">
<button type="submit" [disabled]="!form.valid">Submit</button>
</div>
</form>
You could add a validation to your formGroup and use the formGroup to set the button disabled:
on your component:
constructor(fb:FormBuilder
(...)
) {
this.productForm = fb.group({
name: [null, Validators.required]
(...)
})
}
then on your template, adjust the button:
<button mat-raised-button color="primary" [disabled]="productForm.invalid" (click)="saveProduct()">Save</button>
You might as well remove the 'required' from you input (as angular will warn you about this in the console):
<input formControlName="name" matInput placeholder="Name" style="text-transform:uppercase">

Angular-material, how to bind an object array

I'm dealing with this code which was written by another developer, and I'm not used to angular.
I'm trying to bind the data.order.order_items to an object in the component, to do an additional logic in the component side when the user clicks the button.
<!-- some code -->
<form class="form">
<h4 class="sku-list-title">SKU List</h4>
<mat-slide-toggle
[checked]="isChecked"
(change)="isChecked = $event.source.checked"
class="toggle"
>Edit SKUs</mat-slide-toggle
>
<div
class="item-container"
*ngFor="let element of data.order.order_items"
[(ngModel)]="orderItems"
>
<mat-form-field>
<mat-label>SKU</mat-label>
<input
[value]="element.item.seller_sku"
matInput
tabindex="-1"
[disabled]="true"
/>
</mat-form-field>
<mat-form-field>
<mat-label>New SKU</mat-label>
<input
[placeholder]="element.item.new_seller_sku"
matInput
tabindex="-1"
[disabled]="!isChecked"
/>
</mat-form-field>
<mat-form-field>
<mat-label>Quantity</mat-label>
<input
matInput
maxlength="5"
[value]="element.quantity"
tabindex="-1"
[disabled]="!isChecked"
/>
</mat-form-field>
</div>
</form>
</div>
<!-- some code -->
<div mat-dialog-actions class="actions full-width">
<button mat-flat-button color="warn" (click)="onNoClick()">Cancel</button>
<button
mat-flat-button
color="primary"
(click)="onClick()"
[mat-dialog-close]="closeAnswer"
>
Accept
</button>
</div>
Component side
#Component({
selector: "app-message-dialog",
templateUrl: "./message-dialog.component.html",
styleUrls: ["./message-dialog.component.scss"],
})
export class MessageDialogComponent implements OnInit {
orderItems: any; //This object would bind the order_items
//some code
onClick() {
//some code
this.orderItems //doesn't get the binded data.
How can I bind the data from the data.order.order_items that is updated in that input, to the object this.orderItems?
I tried with the ngModel, but I guess i'm missing something or doing it in the wrong element.
Thanks in advance!
you are binded the data but forgot to display data you can use following syntax {{element }}
you should use the ngModel inside input tag to get the value from corresponding input tag or another option is to use formControl to get the value
NG Model
<input
matInput
maxlength="5"
[value]="element.quantity"
tabindex="-1"
[disabled]="!isChecked"
[(ngModel)]="orderItems"
/>
Form Control
visit this site -> https://angular.io/api/forms/FormControl

*ngIf with button, disabled or not disabled Angular 9

I have two drop downs that are parameters for a function that is called on the Retrieve button click. What I want to happen is when both drop downs do not have data selected, the Retrieve button is disabled. If both drop downs have data then I want the button to act normally.
Here is my current html:
<div class="dropdown">
<div class="input-group">
<h4 class="sessionText">Session: </h4>
<select [(ngModel)]='sessionReportFilter.sessionName'
class="custom-select form-control-sm"
(change)='sessionDataChange($event)'
id="inputGroupSelect01">
<option [value]="null">Select session...</option>
<option *ngFor="let session of sessionData" [value]='session.sessionName'>
{{session.sessionName}}
</option>
</select>
</div>
<div class="input-group">
<h4 class="reportText">Report Date: </h4>
<select [(ngModel)]='sessionReportFilter.fileName' *ngIf='currentSession' class="custom-select form-control-sm" id="inputGroupSelect01">
<option [value]="null">Select report...</option>
<option *ngFor="let report of currentSession.reportFiles"
[value]="report">
{{report}}
</option>
</select>
<select *ngIf="currentSession === null" class="custom-select form-control-sm" id="inputGroupSelect01"></select>
</div>
<div>
<button type="button" class="btn btn-primary" disabled="disabled">Retrieve</button>
<button type="button" class="btn btn-primary" (click)="orderExceptionReportData()">Retrieve</button>
</div>
</div>
How can I achieve the desired results?
[disabled]="!sessionReportFilter.fileName && !sessionReportFilter.sessionName"
Replace that where you want the disabled button when at least one dropdown don't have a value,
so
<button type="button" class="btn btn-primary" disabled="disabled">Retrieve</button>
would be
<button type="button" class="btn btn-primary" [disabled]="!sessionReportFilter.fileName && !sessionReportFilter.sessionName">Retrieve</button>
You can use angular reactive forms validations to solve this problem easily, all you need to do is to put your HTML script and link it to formControlName, the typescript will handle it all:
Suppose we have two select lists, one is for foods and the other for the cars, we need to enable the submit button only if both of the lists are selected (hold values that has been entered by the user), that means that these two fields must be required, we can mark them as required by using angular built-in validation called required, angular will mark the whole form as invalid if one validation is not validated to true, in the HTML script we can make use of the form's status to enable or disable the submit button:
typescript code:
export class SelectOverviewExample {
foods: Food[] = [
{value: 'steak-0', viewValue: 'Steak'},
{value: 'pizza-1', viewValue: 'Pizza'},
{value: 'tacos-2', viewValue: 'Tacos'}
];
form : FormGroup;
constructor(private fb: FormBuilder){
this.createForm();
}
createForm(){
this.form = this.fb.group({
foods: [{value: '', disabled: false}, [Validators.required]],
cars: [{value: '', disabled: false}, [Validators.required]],
});
}
onSubmit(){
// get the values of the form that has been enterd by the user
console.log(this.form.value);
}
}
HTML script:
<h4>Basic mat-select</h4>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<mat-form-field>
<mat-label>Favorite food</mat-label>
<mat-select formControlName="foods">
<mat-option *ngFor="let food of foods" [value]="food.value">
{{food.viewValue}}
</mat-option>
</mat-select>
</mat-form-field>
<br>
<mat-form-field>
<mat-label>Cars</mat-label>
<select matNativeControl formControlName="cars">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
</mat-form-field>
<br>
<button mat-raised-button color="primary" cdkFocusInitial class="col-md-3" type="submit"
[disabled]="!form.valid">Submit</button>
</form>
Live demo (stackblitz reproduction):
https://stackblitz.com/edit/angular-x9nuhj?file=src%2Fapp%2Fselect-overview-example.html
HTML:
<button [disabled]="yourFunctionError" nz-button nzType="primary">Submit</button>
TS:
export class yourComponent implements OnInit {
yourFunctionError: string;
constructor() { }
ngOnInit(): void {
});
this.yourFunctionError= true; //Use your logic
}

Set initial value to a Toggle of a form in Angular Material within HTML

I am working with a simple form:
HTML
<mat-card>
<form (submit)="onAddBet(betForm)" #betForm="ngForm">
<mat-form-field>
<textarea #description="ngModel" matInput rows="6" placeholder="Description" name="description" ngModel
required></textarea>
<mat-error *ngIf="description.invalid">Please enter a Bet Description</mat-error>
</mat-form-field>
<mat-slide-toggle #privacy="ngModel" name="privacy" ngModel>Private</mat-slide-toggle>
<mat-slide-toggle #comments="ngModel" name="comments" ngModel>Allow comments</mat-slide-toggle>
<button mat-raised-button color="primary" type="submit">
CREATE
</button>
</form>
</mat-card>
If I press submit without touching any field of the form I get all the fields empty as it should be expected but I would like to get instead of the status of the form, meaning all the fields as "" but in the fields "privacy" and "comments" as false (boolean) (the default appearance of the toggles is as not marked).
I know that this could be easily done by Typescript from the component following the method:
Typescript
onAddBet(form: NgForm) {
if (!form.value.privacy) {
form.value.privacy = false;
console.log(form.value);
} else console.log(form.value);
if (form.invalid) return;
form.resetForm();
}
But I was wondering if there is any HTML attribute to run the same code avoiding to use Typescript
How could I do it?
You can initialize your ngModel in your HTML by using ngModel with a one-way binding
<mat-slide-toggle #privacy="ngModel" name="privacy" [ngModel]="false">Private</mat-slide-toggle>
<mat-slide-toggle #comments="ngModel" name="comments" [ngModel]="false">Allow comments</mat-slide-toggle>
Then in your component
onAddBet(form: NgForm) {
console.log(form.value);
if (form.invalid) return;
form.resetForm();
}
As per the documentation of slide-toggle you can use [checked]="checked" in HTML.

Angular 2 - Dropdown validation issue

i have tried with many ways:
Validation for select field angular 2
How to apply required validation to dropdown in angular 2
This help me to add validation in dropdown. but i have a issue that validation run properly but when i click on submit button it submit the form if dropdown value is valid or not. i do not want to submit my form if the value of dropdown is "select".
this is my HTML code:
<form name="form" (ngSubmit)="f.form.valid && SaveSymbol()" #f="ngForm" novalidate>
<div class="form-group" [ngClass]="{ 'has-error': f.submitted && !DisplayGroupID.valid && !manageSymbolViewModel.DisplayGroupID }">
<label for="DisplayGroupID">Display Group</label>
<select class="form-control" name="manageSymbolViewModel.DisplayGroupID" #DisplayGroupID id="manageSymbolViewModel.DisplayGroupID" [(ngModel)]="manageSymbolViewModel.DisplayGroupID" required>
<option value="0" selected disabled>Select</option>
<option *ngFor="let group of result.DisplayGroups" value={{group.DisplayGroupId}}>
{{group.DisplayGroup}}
</option>
</select>
<div *ngIf="f.submitted && !DisplayGroupID.valid && !manageSymbolViewModel.DisplayGroupID" class="help-block">Display Group is required</div>
</div>
<div class="form-group">
<button [disabled]="loading" type="submit" class="btn btn primary">Save</button>
<a [routerLink]="['/login']" class="btn btn-link">Cancel</a>
</div>
</form>
This is component code:
SaveSymbol() {
this.manageSymbolService.Save(this.manageSymbolViewModel).subscribe(data => {
debugger;
},
error => {
// this.alertService.error(error);
// this.loading = false;
});
}
}
The first and selected option of your select element has a value 0. So it basically it already has a value set to it on page load.
Try to change it to: <option value="" selected disabled>Select</option> and see if that fixes your problem.
Try this
<button [disabled]="loading || !DisplayGroupID.valid || !manageSymbolViewModel.DisplayGroupID" type="submit" class="btn btn primary">Save</button>
This will prevent the form from submitting while there is nothing selected in the dropdown or when the dropdown model is invalid.
please change your form as given below and also pass your status of form through submit function if required
<form #f="ngForm" (submit)="f.valid && SaveSymbol(f.value, f.valid)" novalidate>
<div class="form-group">
<label>Display Group</label>
<select ngControl="DisplayGroupID" #DisplayGroupID="ngForm" [(ngModel)]="manageSymbolViewModel.DisplayGroupID" required>
<option value='' disabled>Select</option>
<option *ngFor="let group of DisplayGroups" value={{group.DisplayGroupId}}>{{group.DisplayGroup}}</option>
</select>
<small [hidden]="DisplayGroupID.valid || (DisplayGroupID.pristine && !submitted)" class="text-danger">
Displaygroup is required
</small>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
and initialise the model as
this.manageSymbolViewModel = {
DisplayGroupID: ''
};
refer this plunkr http://plnkr.co/edit/sFTM22xbZSXBLZcv90o2
If I'm reading your question right...
Your first value will be 0. So simply set your [disabled] attribute accordingly.
Example: [disabled]="loading || DisplayGroupId.value == 0"
Your button will not be enabled while the first option is selected. Simple solution.