FormControl is not provided by any applicable directives - html

FormControl is having difficulties with directives...
I am trying to implement an autocomplete into my input field. I am using the following angular-material guide to the point that I have verbatim copy and pasted their typescript and html to test it out: https://material.angular.io/components/autocomplete/overview.
I keep receiving an error on FormControl in the HTML that reads: "Property FormControl is not provided by any applicable directives nor by input element. Inspection info: Reports undefined property, event or structural directive bindings on elements."
HTML CODE:
<form class="example-form">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Pick one" aria-label="Number" matInput [FormControl]="myControl" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option">
{{option}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>
TS CODE:
import {Component, OnInit} from '#angular/core';
import {FormControl} from '#angular/forms';
import {Observable} from 'rxjs';
import {map, startWith} from 'rxjs/operators';
#Component({
selector: 'mySelector',
templateUrl: 'myTemplate.html',
styleUrls: ['myCSS.css'],
})
export class myExportClass implements OnInit {
myControl = new FormControl();
options: string[] = ['One', 'Two', 'Three'];
filteredOptions: Observable<string[]>;
ngOnInit() {
this.filteredOptions = this.myControl.valueChanges
.pipe(
startWith(''),
map(value => this._filter(value))
);
}
private _filter(value: string): string[] {
const filterValue = value.toLowerCase();
return this.options.filter(option =>
option.toLowerCase().includes(filterValue));
}
}

As stated in the docs: "For this example, be sure to import ReactiveFormsModule from #angular/forms into your NgModule"
So ensure that your app.module contains the module e.g.:
import {FormsModule, ReactiveFormsModule} from '#angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent,
],
imports: [
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

Related

Mat error is not working in the Angular following code?

I want to know why Mat error is not working in the Angular following code?
<div class="form-group">
<mat-form-field class="row-styling">
<mat-label for="aplctnName">
Application Name <span class="text-danger font-weight-bold">*</span>
</mat-label>
<input
matInput
type="text"
placeholder="Enter Application Name here"
alphabetOnly
maxlength="40"
formControlName="aplctnName"
[ngClass]="{ 'is-invalid': submitted && fields.aplctnName.errors }"
/>
<mat-error *ngIf="fields.aplctnName.errors.required"
>Application Name is required</mat-error
>
error>
</mat-form-field>
</div>
In the following code, mat-error is not working whenever I am pressing the next button.
can anyone please help in resolving this issue ?
You can check my solution.
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { MatFormFieldModule } from '#angular/material/form-field';
import { MatInputModule } from '#angular/material/input';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
#NgModule({
imports: [ BrowserModule, FormsModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, BrowserAnimationsModule ],
declarations: [ AppComponent, HelloComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
styles.scss
/* Add application styles & imports to this file! */
#import "#angular/material/prebuilt-themes/deeppurple-amber.css";
app.component.ts
import { Component, VERSION, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
form: FormGroup;
submitted: boolean = false;
ngOnInit() {
this.form = new FormGroup({
aplctnName: new FormControl('', Validators.required)
});
console.log(this.form)
}
onSubmit(event) {
}
}
app.component.html
<form [formGroup]="form" (ngSubmit)="onSubmit($event)">
<div class="form-group">
<mat-form-field class="row-styling">
<mat-label for="aplctnName">
Application Name <span class="text-danger font-weight-bold">*</span>
</mat-label>
<input
matInput
type="text"
placeholder="Enter Application Name here"
alphabetOnly
maxlength="40"
formControlName="aplctnName"
[ngClass]="{ 'is-invalid': submitted && form.get('aplctnName').errors }"
/>
<mat-error *ngIf="form.get('aplctnName').errors?.required"
>Application Name is required</mat-error
>
</mat-form-field>
<button type="submit">submit</button>
</div>
</form>
you can check working demo here
Let me know if you still face any issue.

Angular9-MatDatePicker: Can't bind to 'ngModel' since it isn't a known property of 'input'

I have looked at SEVERAL other posts about this and I'm still having a problem implementing ngmodel binding with matdatepicker.
My HTML:
<mat-form-field>
<mat-label>Start Date</mat-label>
<input matInput [(ngModel)]="searchStartDate" [min]="minDate" [max]="maxDate" [matDatepicker]="picker">
<mat-datepicker-toggle matSuffix [for]="picker">
</mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
I get this error for the html code above: Can't bind to 'ngModel' since it isn't a known property of 'input'.
TS file associated with html code above:
import { Component, OnInit } from '#angular/core';
import { FormsModule,ReactiveFormsModule } from '#angular/forms';
// I threw this in just in case^^
#Component({
selector: 'app-dash-home',
templateUrl: './example.component.html',
styleUrls: ['./example.component.scss']
})
export class ExampleComponent implements OnInit {
searchStartDate: Date; searchEndDate: Date
constructor() {
const todaysDate = new Date();
this.minDate = new Date(todaysDate.getFullYear() - 5, 0, 1);
this.maxDate = new Date(todaysDate.getFullYear(), todaysDate.getMonth(), todaysDate.getDate());
}
ngOnInit() {
}
}
I have been trying to debug this issue for several hours now and I'm not sure if this is an Angular v9 issue.
I found a stackblitz example from another stackoverflow question which illustrates the expected behavior here (running Angular v7 I think): https://stackblitz.com/edit/angular-y8hqyn-52t76k?file=app%2Fdatepicker-value-example.html
Notice how the stackblitz example initializes to today's date? That's the behavior I'm trying to emulate. I also included my app.module.ts below just in case.
File: app.module.ts
import { FormsModule, ReactiveFormsModule} from '#angular/forms';
imports: [...
FormsModule,
...]
Thanks for all the anticipated help and support
EDIT:
Adding the module files for which ExampleComponent belongs to:
examplecomponent.module.ts:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { MaterialModule } from '../../assets/material';
import { FormsModule } from '#angular/forms';
#NgModule({
declarations: [...],
imports: [
...,
FormsModule
]
})
export class ExampleComponentModule{ }
You need to make sure that the FormsModule is imported in the module that your ExampleComponent is declared

Angular materials working in one component but not another

I've been working in Angular for the first time for a school-related project. I'm trying to make my pages look a bit better by using materials for form inputs instead of the stock HTML forms, and to great success in most of my components. However, one component in particular isn't recognizing the material tags as valid even though they work fine in the others with no discernible (to me) differences in either the .HTML file implementation or the .ts file declarations and imports.
They work in my sign in component, as shown below.
sign-in.component.html
<form [formGroup]="signInForm" (ngSubmit)="onSubmit(signInForm.value)">
<mat-form-field>
<mat-label>Employee ID:</mat-label>
<input matInput type="number" formControlName="employeeId">
</mat-form-field>
<br>
<mat-form-field>
<mat-label>Password:</mat-label>
<input matInput type="password" formControlName="password">
</mat-form-field>
<br>
<button mat-raised-button type="submit">Sign In</button>
<br>
</form>
The relevant .ts file is here. This isn't all of it, just the imports and declarations.
sign-in.component.ts
import { Component, OnInit} from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { FormGroup, FormControl } from '#angular/forms';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { environment } from '../../../environments/environment';
import { EmployeeService } from 'src/app/employee/employee.service';
import { Employee } from 'src/app/employee/employee';
#Component({
selector: 'sign-in',
templateUrl: './signin.component.html',
styleUrls: ['./signin.component.css']
})
export class SigninComponent implements OnInit{
private apiUrl = environment.baseUrl + "/api/auth";
signInForm = new FormGroup({
employeeId: new FormControl(''),
password: new FormControl(''),
});
errorMsg = null
constructor(
private employeeService: EmployeeService,
private activatedRoute: ActivatedRoute,
private router: Router,
private http: HttpClient
){}
}
When I try to implement almost the exact same code in my other component, it isn't recognizing the labels.
product-detail.component.html
<h1><b>PRODUCT DETAILS</b></h1>
<form [formGroup]="productDetailsForm" (ngSubmit)="onSubmit(productDetailsForm.value)">
<div>
<mat-form-field>
<mat-label for="name">Name</mat-label>
<input matInput id="name" type="text" formControlName="name">
</mat-form-field>
</div>
<div>
<mat-form-field>
<mat-label for="price">Price</mat-label>
<input matInput id="price" type="number" formControlName="price">
</mat-form-field>
</div>
<div>
<mat-form-field>
<mat-label for="lookupCode">Name</mat-label>
<input matInput id="lookupCode" type="text" formControlName="lookupCode">
</mat-form-field>
</div>
<div>
<mat-form-field>
<mat-label for="count">Price</mat-label>
<input matInput id="count" type="number" formControlName="count">
</mat-form-field>
</div>
<button *ngIf="isManager" class="button" type="submit">Save</button>
</form>
<button mat-raised-button *ngIf="isManager" class="button" (click)="deleteClicked()">Delete</button>
The relevant .ts file is below.
product-detail.component.ts
import { Component, OnInit, Input } from '#angular/core';
import { FormBuilder, FormGroup, Validators, FormControl } from '#angular/forms';
import { Product } from '../product';
import { ProductService } from '../product.service';
import { ActivatedRoute, Router } from '#angular/router';
import { UserService } from '../../services/user.service';
import { MatFormFieldModule } from '#angular/material/form-field';
#Component({
selector: 'product-detail-t',
templateUrl: './product-detail.component.html',
styleUrls: ['./product-detail.component.css'],
providers: [ProductService, UserService]
})
export class ProductDetailComponent implements OnInit {
#Input() id: string;
productDetailsForm: FormGroup;
isManager: boolean;
constructor(
private productService: ProductService,
private userService: UserService,
private formBuilder: FormBuilder,
private activatedRoute: ActivatedRoute,
private router: Router
) {
this.id = this.activatedRoute.snapshot.paramMap.get("id");
this.productDetailsForm = this.formBuilder.group({
lookupCode: new FormControl({value: '', disabled: true}),
price: new FormControl({value: '', disabled: true}),
name: new FormControl({value: '', disabled: true}),
count: new FormControl({value: '', disabled: true})
});
this.userService.isManager()
.then((isManager: boolean) => {
this.isManager = isManager;
if(isManager) {
this.productDetailsForm.controls["name"].enable();
this.productDetailsForm.controls["lookupCode"].enable();
this.productDetailsForm.controls["count"].enable();
this.productDetailsForm.controls["price"].enable();
}
});
}
}
Below is my app.module.ts file, if that helps.
import { BrowserModule } from '#angular/platform-browser';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { NgModule } from '#angular/core';
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { ReactiveFormsModule } from '#angular/forms';
import { MatButtonModule } from '#angular/material/button';
import { MatCardModule } from '#angular/material/card';
import { MatInputModule } from '#angular/material/input';
import { MatFormFieldModule } from '#angular/material/form-field';
import { MatToolbarModule } from '#angular/material/toolbar';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { EmployeeModule } from './employee/employee.module';
import { ProductModule } from './product/product.module';
import { TransactionModule } from './transaction/transaction.module';
import { SigninComponent } from './components/signin/signin.component';
import { MainMenuComponent } from './components/main-menu/main-menu.component';
import { PageHeaderComponent } from './components/page-header/page-header.component';
import { HttpRequestInterceptor } from './HttpInterceptor';
import { TransactionPageComponent } from './transaction/transaction-page/transaction-page.component';
#NgModule({
declarations: [
AppComponent,
SigninComponent,
MainMenuComponent,
SigninComponent,
PageHeaderComponent,
TransactionPageComponent
],
imports: [
BrowserModule,
ReactiveFormsModule,
HttpClientModule,
EmployeeModule,
AppRoutingModule,
BrowserModule,
BrowserAnimationsModule,
ProductModule,
MatButtonModule,
MatCardModule,
MatInputModule,
MatFormFieldModule
],
exports: [
MatButtonModule,
MatCardModule,
MatInputModule,
MatFormFieldModule
],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: HttpRequestInterceptor, multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule { }
I should mention that the form in the sign-in component was created by one of my group members, but he can't seem to find the problem with my code either.
Any help at all would be greatly appreciated!
You're getting that error probably because you have not imported the MatInputModule or any other Angular Material modules in the ProductModule where I believe your ProductDetailComponent is declared.

How to use Mat-Select with property [Selected]

I have a component which allows for translate pipng(by .json files under assets) .That works perfectly with default select box to choose language as we wish to display.Here it is below(That works great)
<select #langSelect (change)="translate.use(langSelect.value)">
<option *ngFor="let lang of translate.getLangs()"
[value]="lang"
[selected]="lang === translate.currentLang">{{ lang }}
</option>
</select>
But to make it look much better,I want to implement this logic with mat-select and here how I tried to implement below.
With Mat-Select
<mat-form-field>
<mat-select #langSelect (change)="translate.use(langSelect.value)"
placeholder="Select offer"
formControlName="promo" [(value)]="selected">
<mat-option *ngFor="let lang of translate.getLangs()"
[value]="lang"
[selected]="lang === translate.currentLang"
>{{ lang }}
<i class="material-icons">info</i>
</mat-option>
</mat-select>
</mat-form-field>
When I run this code Error occurs because of unknown [selected] binding inside mat-option tags.I don't know is there any way to implement it with no error.Here that error in the console occurs below
ERROR
Uncaught Error: Template parse errors:
No provider for NgControl ("">{{ lang }}</option>
</select> -->
[ERROR ->]<select #langSelect (change)="translate.use(langSelect.value)" placeholder="Select offer" formContro"): ng:///AppModule/HeaderComponent.html#17:34
App.Module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import {BrowserAnimationsModule} from '#angular/platform-browser/animations';
import {FlexLayoutModule} from '#angular/flex-layout';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MaterialModule } from './material.module';
import { SignupComponent } from './auth/signup/signup.component';
import { LoginComponent } from './auth/login/login.component';
import { TrainingComponent } from './training/training.component';
import { CurrentTrainingComponent } from './training/current-training/current-training.component';
import { NewTrainingComponent } from './training/new-training/new-training.component';
import { PastTrainingComponent } from './training/past-training/past-training.component';
import { WelcomeComponent } from './welcome/welcome.component';
import { FormsModule } from '#angular/forms';
import { HeaderComponent } from './navigation/header/header.component';
import { SidenavListComponent } from './navigation/sidenav-list/sidenav-list.component';
import { StopTrainingComponent } from './training/current-training/stop-training-component';
import { AuthService } from './auth/auth.service';
import {TranslateModule, TranslateLoader} from '#ngx-translate/core';
import {TranslateHttpLoader} from '#ngx-translate/http-loader';
import { HttpClient, HttpClientModule } from '#angular/common/http';
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient);
}
#NgModule({
declarations: [
AppComponent,
SignupComponent,
LoginComponent,
TrainingComponent,
CurrentTrainingComponent,
NewTrainingComponent,
PastTrainingComponent,
WelcomeComponent,
HeaderComponent,
StopTrainingComponent,
SidenavListComponent
],
imports: [
BrowserModule,
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
}),
FormsModule,
AppRoutingModule,
BrowserAnimationsModule,
MaterialModule,
FlexLayoutModule
],
//To use always same AuthService object
providers: [AuthService],
bootstrap: [AppComponent],
entryComponents:[StopTrainingComponent]
})
export class AppModule { }
You can check documentation and examples here:
https://material.angular.io/components/select/examples
There is also a selected example.
First problem is, selected is not available for mat-option.
What you need to do is, on your component.ts file you need to find selected element from your array, and set it to a variable.
Then in your mat-select, set [(value)] attribute as that variable. It will make it selected.
Example:
<mat-select [(value)]="selected">
<mat-option>None</mat-option>
<mat-option value="option1">Option 1</mat-option>
<mat-option value="option2">Option 2</mat-option>
<mat-option value="option3">Option 3</mat-option>
</mat-select>

Why is my code for 'mat-form-field' not working?

I'm totaly new to angular, and i was practicing using material and adding form fields. I followed all the guides, downloaded all the packages and my code is just copy-pased from a guide but it's still not displaying on my browser.
My console initialy showed
"Unexpected directive 'MatFormField' imported by the module 'AppModule'. Please add a #NgModule annotation."
and after googling it I was told to replace it with "MatFormFieldModule" but after i did i got this error
"NullInjectorError: StaticInjectorError(AppModule)[CdkObserveContent -> ElementRef]:
StaticInjectorError(Platform: core)[CdkObserveContent -> ElementRef]:
NullInjectorError: No provider for ElementRef!"
My code:
app.component.html
<p>works</p>
<form class = "tp-form">
<mat-form-field class = "tp-full-width">
<input matInput placeholder = "Favorite Food" value = "Pasta">
</mat-form-field>
<mat-form-field class = "tp-full-width">
<textarea matInput placeholder = "Enter your comment"></textarea>
</mat-form-field>
<mat-form-field class = "tp-full-width">
<input matInput placeholder = "Email" [formControl] =
"emailFormControl">
<mat-error *ngIf = "emailFormControl.hasError('email')
&& !emailFormControl.hasError('required')">
Please enter a valid email address
</mat-error>
<mat-error *ngIf = "emailFormControl.hasError('required')">
Email is <strong>required</strong>
</mat-error>
</mat-form-field>
</form>
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { CourseComponent } from './course/course.component';
import {BrowserAnimationsModule} from '#angular/platform-
browser/animations';
import {MatInputModule, MatFormField, MatFormFieldModule} from
'#angular/material'
import {FormsModule, ReactiveFormsModule} from '#angular/forms';
import { CUSTOM_ELEMENTS_SCHEMA } from '#angular/core';
const modules = [
BrowserAnimationsModule,
MatInputModule,
FormsModule,
ReactiveFormsModule,
MatFormFieldModule
]
#NgModule({
declarations: [
AppComponent,
CourseComponent
],
imports: [
BrowserModule,
AppRoutingModule,
...modules
],
exports:[
...modules
],
providers: [],
bootstrap: [AppComponent]
,
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }
app.component.ts
import { Component } from '#angular/core';
import { FormControl } from "#angular/forms";
import { Validators } from '#angular/forms';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'materialApp';
emailFormControl = new FormControl('', [
Validators.required,
Validators.email,
]);
}
Currently my browser is only showing "works".
emailFormControl should be define with ViewChild annotation, like this:
import { Component, ElementRef, ViewChild } from '#angular/core'
...
#ViewChild('emailFormControl') emailFormControl: ElementRef
In short, ViewChild allows us to query elements (from the docs: https://angular.io/api/core/ViewChild)
In this example we used the query target our emailFormControl an get a valid reference