On dev brach,I have implemented MatFormFieldControl then use it inside mat-form-field . I also pack it (tgz) to use as lib.
On main site there is error said "mat-form-field must contain a MatFormFieldControl." even though it work perfectly on dev.
PS. I'm not english native. Pardon me if I make you confused
how i use it
<mat-form-field>
<ax-mat-time-picker></ax-mat-time-picker>
</mat-form-field>
this is template
<div [formGroup]="parts">
<input matInput type="number" >
<input matInput type="number" >
<input matInput type="number">
<input matInput type="text">
</div>
this is typescript
#Component({
selector: 'ax-mat-time-picker',
exportAs: 'axMatTimePicker',
templateUrl: './time-picker.component.html',
styleUrls: ['./time-picker.component.scss'],
encapsulation: ViewEncapsulation.None,
preserveWhitespaces: false,
providers: [
{ provide: MatFormFieldControl, useExisting: AxMatTimePicker },
DecimalPipe
],
host: {
'class': 'ax-mat-time-picker',
'[class.floating]': 'shouldLabelFloat',
'[id]': 'id',
'[attr.aria-describedby]': 'describedBy'
}
})
export class AxMatTimePicker implements MatFormFieldControl<Time>, OnDestroy {...}
I believe your issue is that each of the fields in your form is not bound to data in the TS.
You should change your template to actually use a form and create a formGroup with values that your form values can bind to. You do this with the "formControlName" directive in the HTML and a "FormGroup" object containing "FormControl" elements in the TS.
Don't forget to import "ReactiveFormsModule" in your module.ts and "AbstractControl, FormBuilder, FormControl, FormGroup, FormArray" in your component.ts.
Example:
HTML
<form [formGroup]="form">
<mat-form-field>
<input matInput formControlName="name" placeholder="Name">
</mat-form-field>
<mat-form-field>
<input matInput formControlName="email" placeholder="Email">
</mat-form-field>
</form>
TS
form = new FormGroup({
name: new FormControl(),
email: new FormControl()
});
Related
I'm just starting to learn laravel+vue. I was able to follow a tutorial from this yt: https://www.youtube.com/watch?v=JZDmBWRPWlw. Though it seems outdated, I was still able to follow his steps. I'm using the laravel-mix 6.0.6 and vue 2.6.12.
Using inspect element>network, I can see that I'm throwing the correct error message in array.
{"component":"Users\/Create","props":{"app":{"name":"Laravel"},"errors":{"name":"The name field is required.","email":"The email field is required."}},"url":"\/users\/create","version":"207fd484b7c2ceeff7800b8c8a11b3b6"}
But somehow it is not displaying the complete error message. Right now it just show the first letter of the sentence. LOL. Sample error message is: The email field is required and it will just display the letter "T". Below is my Create.vue. Basically it is just a user create form with simple validation.
Create.vue
<template>
<layout>
<div class="container">
<div class="col-md-6">
<div v-if="Object.keys(errors).length > 0" class="alert alert-danger mt-4">
{{ errors[Object.keys(errors)[0]][0] }}
</div>
<form action="/users" method="POST" class="my-5" #submit.prevent="createUser">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" placeholder="Name" v-model="form.name">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control" id="email" placeholder="Email" v-model="form.email">
</div>
<div class="form-group">
<label for="name">Password</label>
<input type="password" class="form-control" id="password" placeholder="Password" v-model="form.password">
</div>
<button type="submit" class="btn btn-primary">Create User</button>
</form>
</div>
</div>
</layout>
</template>
<script>
import Layout from '../../Shared/Layout'
export default {
props: ['errors'],
components: {
Layout,
},
data() {
return {
form: {
name: '',
email: '',
password: '',
}
}
},
methods: {
createUser() {
this.$inertia.post('/users', this.form)
.then(() => {
// code
})
}
}
}
</script>
Edit:
I have this error on my console
[Vue warn]: Error in v-on handler: "TypeError: Cannot read property
'then' of undefined"
found in
---> at resources/js/Pages/Users/Create.vue
Your error call is probably getting only the first letter due to [0]. Try to change to:
{{ errors[Object.keys(errors)[0]] }}
Strings can also be read as arrays. If you do this:
$a = "TEST";
echo $a[0];
That would print only T.
That is probably the problem.
I have the following code
<form #createForm="ngForm">
<mat-form-field>
<mat-select placeholder="Favorite food"
matInput
[ngModel]
food="food"
#food="ngModel" required>
<mat-option *ngFor="let food of foods" [value]="food.value">
{{ food.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>
</form>
<button [disabled]="!createForm.valid">submit</button>
Since I want the "selection" is a required field, the "submit" button should be disabled when the form is rendered. However, the "submit" button is enabled when the form is displayed. What is the problem?
This works for me when I (a) use a name attribute and (b) use the two-way ngModel binding syntax.
i.e. Instead of this
<mat-select placeholder="Favorite food" matInput [ngModel] food="food" #food="ngModel" required>
use this:
<mat-select name="food" placeholder="Favorite food" [(ngModel)]="food" required>
for validation in angular 5 use reactive forms. refer this
*** componenet.ts *******
import { FormControl, Validators, FormBuilder, FormGroup, ReactiveFormsModule, NgForm } from '#angular/forms';
export class Test implements OnInit{
foodform:FormGroup;
constructor(){}
ngOnInit() {
// create form group of controls
this.foodform = new FormGroup({
favoriteFood: new FormControl('', [Validators.required])
});
}
}
**** Component.html************
<form #createForm="ngForm" [formGroup]="foodform ">
<mat-form-field>
<mat-select placeholder="Favorite food"
matInput
[ngModel]
food="food"
#food="ngModel" formControlName="favoriteFood">
<mat-option *ngFor="let food of foods" [value]="food.value" >
{{ food.viewValue }}
</mat-option>
</mat-select>
<mat-error *ngIf="foodform.controls['favoriteFood'].hasError('required') && foodform.controls['favoriteFood'].pristine">
Required Message
</mat-error>
</mat-form-field>
</form>
use [formGroup] and formControlName in your html form.
The only way required field validation works on a mat-select is by using reactive form validation. Just import the respective components in typescript file:
import {FormControl, Validators} from '#angular/forms';
HTML file :
Remove your ngModel reference
<mat-form-field>
<mat-select placeholder="Favorite food"
matInput [formControl]="foodControl"
required>
<mat-option *ngFor="let food of foods" [value]="food.value">
{{ food.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>
This works for the required field validation. If you wanted to validate more probably you will end up accessing the form in the typescript file. Its weird that there is no option to do form validation, this is the only way i found to make it work.
Look at danger89's comment under your original question.
You are missing the name attribute.
E.g:
<form #createForm="ngForm" (ngSubmit)="submitFunction(createForm)">
<mat-form-field>
<mat-select
placeholder="Favorite food"
ngModel
name="food"
required
>
<mat-option *ngFor="let food of foods" [value]="food.value">
{{ food.viewValue }}
</mat-option>
</mat-select>
</mat-form-field>
<button type="submit" [disabled]="!createForm.valid">submit</button>
</form>
Because of the name attribute, your food.value can now be found at createForm.value.food when submitting the form.
This worked for me:
Import ReactiveFormsModule in you app module
import { ReactiveFormsModule } from '#angular/forms';
and add its dependency in #NgModule decorator
I don't know what I'm doing wrong but I can't get any solution to work using Ang8 + Material8 and a multi-select while using a FormGroup and a FormControl. I ended up doing the following as a workaround.
First I added a tag to the mat-select, #thisselect
Then I tested the value of the tag for zero length in the submit button
<form [formGroup]="bypartForm" (ngSubmit)="onSubmit()">
<mat-form-field [hideRequiredMarker]="true">
<mat-select #thisselect placeholder="Brands" formControlName="brands"
(selectionChange)="selectChanged($event)" multiple required>
<mat-option *ngFor="let brand of brandList" [value]="brand.name">{{brand.name}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field [hideRequiredMarker]="true">
<input matInput autocomplete="off" placeholder="Part#" formControlName="part" required>
</mat-form-field>
<div class="form-buttons">
<button mat-raised-button color="primary" type="submit" [disabled]="!bypartForm.valid || (thisselect.value != undefined && thisselect.value.length == 0)">Submit</button>
</div>
</form>
I am new for angular 2. I have a page where we can edit details of customer profile. How to enable save button if any property of has been changed. I know it is possible in angular1 by using $watch.
It is simple. dirty check your form if you are using #angular/forms.
create form
export class HeroDetailComponent4 {
heroForm: FormGroup;
states = states;
constructor(private fb: FormBuilder) {
this.createForm();
}
createForm() {
this.heroForm = this.fb.group({
name: ['', Validators.required ],
street: '',
city: '',
state: '',
zip: '',
power: '',
sidekick: ''
});
}
}
HTML:
<h2>Hero Detail</h2>
<h3><i>A FormGroup with multiple FormControls</i></h3>
<form [formGroup]="heroForm" novalidate>
<button (click)="submit()" [disabled]="!heroForm.dirty" type="button">Submit</button>
<div class="form-group">
<label class="center-block">Name:
<input class="form-control" formControlName="name">
</label>
</div>
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
<div class="form-group radio">
<h4>Super power:</h4>
<label class="center-block"><input type="radio" formControlName="power" value="flight">Flight</label>
<label class="center-block"><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
<label class="center-block"><input type="radio" formControlName="power" value="strength">Strength</label>
</div>
<div class="checkbox">
<label class="center-block">
<input type="checkbox" formControlName="sidekick">I have a sidekick.
</label>
</div>
</form>
use heroForm.dirty to check whether form data is changed. it will set to true if any control inside heroForm has been changed.
<button (click)="submit()" [disabled]="!heroForm.dirty" type="button">Submit</button>
Refer angular docs for more info
you can use form control validation for it.
some thing like this in html template:
<form fxLayout="column" [formGroup]="form">
<mat-form-field class="mb-1">
<input matInput [(ngModel)]="userProfileChangeModel.firstName" placeholder="نام"
[formControl]="form1.controls['fname']">
<small *ngIf="form1.controls['fname'].hasError('required') && form1.controls['fname'].touched"
class="mat-text-warn">لطفا نام را وارد نمایید.
</small>
<small *ngIf="form1.controls['fname'].hasError('minlength') && form1.controls['fname'].touched"
class="mat-text-warn">نام باید حداقل 2 کاراکتر باشد.
</small>
<small *ngIf="form1.controls['fname'].hasError('pattern') && form1.controls['fname'].touched"
class="mat-text-warn">لطفا از حروف فارسی استفاده نمائید.
</small>
</mat-form-field>
<mat-card-actions>
<button mat-raised-button (click)="editUser()" color="primary" [disabled]="!form1.valid" type="submit">
ذخیره
</button>
</mat-card-actions>
</form>
and like this in ts file:
this.form = this.bf.group({
fname: [null, Validators.compose([
Validators.required,
Validators.minLength(2),
Validators.maxLength(20),
Validators.pattern('^[\u0600-\u06FF, \u0590-\u05FF]*$')])],
});
if:
[disabled]="!form1.valid"
is valid save button will be active
bast regards.
You can use disabled option like below :
<button [disabled]="isInvalid()" type="button" (click) = "searchClick()" class="button is-info">
<span class="icon is-small">
<i class="fa fa-search" aria-hidden="true"></i>
</span>
<span>Search</span>
</button>
you can create isInvalid() in your ts file and check if that property is empty or not and return that boolean value
and for hide button on a state you can use *ngIf in line directive.
This worked for me, pls try.
In your html,
<input type="text" [ngModel]="name" (ngModelChange)="changeVal()" >
<input type="text" [ngModel]="address" (ngModelChange)="changeVal()" >
<input type="text" [ngModel]="postcode" (ngModelChange)="changeVal()" >
<button [disabled]="noChangeYet" (click)="clicked()" >
<span>SUBMIT</span>
</button>
In your component
export class customer implements OnInit {
name: string;
address: string;
postcode: string;
noChangeYet:boolean = true;
constructor() {}
changeVal(){ // triggers on change of any field(s)
this.noChangeYet = false;
}
clicked(){
// your function data after click (if any)
}
}
Hope this is what you need.
Finally I resolved this issue.
import { Component, Input, Output, OnInit, AfterViewInit, EventEmitter, ViewChild } from '#angular/core';
#Component({
selector: 'subscribe-modification',
templateUrl: './subscribe.component.html'
})
export class SampleModifyComponent implements OnInit, AfterViewInit {
disableSaveSampleButton: boolean = true;
#ViewChild('sampleModifyForm') sampleForm;
ngAfterViewInit() {
setTimeout(() => {
this.sampleForm.control.valueChanges.subscribe(values => this.enableSaveSampleButton());
}, 1000);
}
enableSaveSampleButton() {
console.log('change');
this.disableSaveSampleButton = false;
}
}
HTML
<button id="btnSave" class="btn btn-primary" (click)="save()" />
I'm using Vue for the first time, with Vue Validator. Here is an example of my code:
<label for="first_name">First name:
<span v-if="$validation1.first_name.required" class="invalid">Enter your first name.</span>
<input id="first_name" placeholder="e.g. Christopher" class="" v-validate:first_name="['required']" v-model="first_name" name="first_name" type="text">
</label>
The only issue at the moment is that when I land on the page with my form, the whole thing is covered in errors. Is there a way I can suppress the errors and only show them on input blur / form submit?
Argh, the Google-able word isn't about blur, or on submit – its about timing and initial:
http://vuejs.github.io/vue-validator/en/timing.html
<input id="first_name" initial="off" placeholder="e.g. Christopher" class="" v-validate:first_name="['required']" v-model="first_name" name="first_name" type="text">
you need to add .dirty or .touched to your validation
<label for="first_name">First name:
<span v-if="$validation1.first_name.required && $validation1.first_name.touched" class="invalid">Enter your first name.</span>
<input id="first_name" placeholder="e.g. Christopher" class="" v-validate:first_name="['required']" v-model="first_name" name="first_name" type="text">
</label>
I was dealing with a similar problem. I had to have an initialized variable for the input name: "" but I also wanted to have a required attribute in element.
So I add required when the event onblur occurs.
<input name="name" type="number" v-model="name" #blur="addRequired" />
const app = Vue.createApp({
data() {
return {
name: ""
}
},
methods:{
addRequired: function(event){
event.target.setAttribute("required", true);
}
}
});
I have a question about how I can implement radio buttons in my form with ngControl
Here is the code of the template:
<div class="form-group">
<label class="radio-inline" *ngFor="#size of formModel.sizes">
<input type="radio" ngControl="ourSize" #ourSize="ngForm" value="{{ size }}" >
{{ size }}
</label>
</div>
here is the code of model:
this.formModel = {
sizes: ['asd1', 'asd2', 'asd3']
}
I have such an error:
P.S. I have already checked another answer Angular2 - Radio Button Binding
but it didn't help me(
You need to use radio inputs this way:
#Component({
selector: 'my-app',
template: `
<form>
<div class="form-group">
<label class="radio-inline" *ngFor="#size of formModel.sizes; #i=index">
<input type="radio" [(ngModel)]="formModel.sizes[i]" #ctrl="ngForm" ngControl="sizeCtrl" name="size"/>
{{ size.value }}
</label>
</div>
Test: {{ctrl?.value}}
Values: {{formModel | json}}
</form>
`
})
export class AppComponent {
constructor() {
this.formModel = {
sizes: [
new RadioButtonState(true, 'asd1'),
new RadioButtonState(false, 'asd2'),
new RadioButtonState(false, 'asd3')
]
};
}
}
The radio button states are updated according what is selected. It doesn't seem that controls can be used at this level...
Se this plunkr: https://plnkr.co/edit/kHJyq3N5ZtoNyAPz6Kbc?p=preview