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.
Related
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.
I have a text box,which only allows to type number,If I try to type alphabet or any special character it should show error below the text box.Once I start typing numeric error should hide.Here I am using reactive form of angular 8. Here is the code below
home.component.html
<form [formGroup]="registerForm" (ngSubmit)="onSubmit()">
<div class="form-row">
<div class="form-group col">
<label>Title</label>
<input type="number" formControlName="title" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.title.errors }"/>
<div *ngIf="submitted && f.title.errors" class="invalid-feedback">
<div *ngIf="f.title.errors.required">Title is required</div>
</div>
</div>
</div>
<div class="text-center">
<button class="btn btn-primary mr-1">Register</button>
<button class="btn btn-secondary" type="reset" >Cancel</button>
</div>
</form>
home.component.ts
import { Component, OnInit } from '#angular/core';
import { CommonserviceService } from './../utilities/services/commonservice.service';
import { FormBuilder, FormControl, FormGroup, Validators } from '#angular/forms';
import {NgbModal, ModalDismissReasons} from '#ng-bootstrap/ng-bootstrap';
declare var $: any;
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
imageSource :any;
statusdata: any;
closeResult: string;
registerForm: FormGroup;
submitted = false;
constructor(private modalService: NgbModal,private formBuilder: FormBuilder) {}
ngOnInit() {
this.statusdata = [
{ id: 1, name: "cat"},
{ id: 2, name: "arctichare"},
{ id: 3, name: "baboon" },
];
this.registerForm = this.formBuilder.group({
title: ['', Validators.required]
});
}
get f() { return this.registerForm.controls; }
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.registerForm.invalid) {
return;
}
// display form values on success
alert('SUCCESS!! :-)\n\n' + JSON.stringify(this.registerForm.value, null, 4));
}
}
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 { UsermanagementComponent } from './usermanagement/usermanagement.component';
import { HomeComponent } from './home/home.component';
import { HeaderComponent } from './shared/header/header.component';
import { LoginComponent } from './login/login.component';
import {HttpModule} from '#angular/http';
import { FormsModule,ReactiveFormsModule } from '#angular/forms';
import {NgbModule} from '#ng-bootstrap/ng-bootstrap';
#NgModule({
declarations: [
AppComponent,
UsermanagementComponent,
HomeComponent,
HeaderComponent,
LoginComponent
],
imports: [
NgbModule,
BrowserModule,
AppRoutingModule,
HttpModule,
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
I think you can catch input values with keydown or keyup.
change your input as following:
<input type="number" formControlName="title" class="form-control"
#inp (keydown)="checkValue($event, inp.value)"
[ngClass]="{ 'is-invalid': submitted && f.title.errors }"/>
And add following method to your component:
checkValue(event: KeyboardEvent, val: any) {
const allowedChars = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, "Backspace", "ArrowLeft", "ArrowRight"];
let isValid: boolean = false;
for (let i = 0; i < allowedChars.length; i++) {
if (allowedChars[i] == event.key) {
isValid = true;
break;
}
}
if (!isValid) {
event.preventDefault();
alert('Enter only number'); // or do smt about your error message
}else{
//reset error status here
}
}
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
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 { }
I make a form with some fields like email user name and avatar using reactive form of angular 6. I know i need form data to upload image, but i dont know how to using it with reactive form in angular 6. Anyone can help ?
Try this:
<form [formGroup]="yourForm" (ngSubmit)="onSubmit()">
<input type="text" formControlName="email"> <br>
<input (change)="uploadDocument($event)" type="file" accept=".png, .pdf, .jpg, .jpeg"> <br>
<input (change)="onSubmit()" type="submit" value="Send file">
</form>
in your app.component.html, then:
import { Component } from '#angular/core';
import { FormBuilder, FormGroup } from '#angular/forms';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
yourForm: FormGroup;
constructor(private fb: FormBuilder, private http: HttpClient) {
this.yourForm = this.fb.group({
email: [''],
file: ['']
});
}
uploadDocument(event: any) {
if (event.target.files && event.target.files[0]) {
const reader = new FileReader();
reader.onload = () => {
this.yourForm.get('file').setValue(event.target.files[0]);
};
reader.readAsDataURL(event.target.files[0]);
}
}
onSubmit(): void {
const uploadData = new FormData();
uploadData.append('email', this.yourForm.get('email').value);
uploadData.append('file', this.yourForm.get('file').value);
this.http.post('your-route', uploadData);
}
}
in your app.component.ts, and:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { HttpClientModule } from '#angular/common/http';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
#NgModule({
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
FormsModule,
ReactiveFormsModule
],
declarations: [AppComponent, HelloComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
in your app.module.ts file.
Also, don't forget to configure the route in line this.http.post('your-route', uploadData);.