binding form using formGroup in angular component - angular-formbuilder

I'm facing below error while binding the form
cart.component.html
<h3>Cart</h3>
<p>
<a routerLink="/shipping">Shipping Prices</a>
</p>
<div class="cart-item" *ngFor="let item of items">
<span>{{ item.name }} </span>
<span>{{ item.price | currency }}</span>
</div>
<form [formGroup]="checkoutForm" (ngSubmit)="onSubmit()">
<div>
<label for="name">
Name
</label>
<input id="name" type="text" formControlName="name">
</div>
<div>
<label for="address">
Address
</label>
<input id="address" type="text" formControlName="address">
</div>
<button class="button" type="submit">Purchase</button>
</form>
cart.component.ts
import { Component } from '#angular/core';
import { FormBuilder } from '#angular/forms';
import { CartService } from '../cart.service';
#Component({
selector: 'app-cart',
templateUrl: './cart.component.html',
styleUrls: ['./cart.component.css']
})
export class CartComponent {
items = this.cartService.getItems();
checkoutForm = this.formBuilder.group({
name: '',
address: ''
});
constructor(
private cartService: CartService,
private formBuilder: FormBuilder,
) {}
onSubmit(): void {
// Process checkout data here
this.items = this.cartService.clearCart();
console.warn('Your order has been submitted', this.checkoutForm.value);
this.checkoutForm.reset();
}
}
error :
Failed to compile.
src/app/cart/cart.component.html:12:7 - error NG8002: Can't bind to 'formGroup' since it isn't a known property of 'form'.
12 <form [formGroup]="checkoutForm" (ngSubmit)="onSubmit()">
~~~~~~~~~~~~~~~~~~~~~~~~~~
src/app/cart/cart.component.ts:8:16
8 templateUrl: './cart.component.html',
~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component CartComponent.

just add into your app.module.ts
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
and under #NgModule
#NgModule({
imports: [
FormsModule,
ReactiveFormsModule,

Related

ERROR Error: No value accessor for form control with name:

I have followed
the following guide
Angular-Reactive forms
I modified a bit the code to put it in a module, adding some fields to the originals model and it worked.
after upgrading to angular 8, the module is still working, but the console in Chrome for every control gives me this error:core.js:6150 ERROR Error: No value accessor for form control with name: 'title' at _throwError (forms.js:2603) at setUpControl (forms.js:2377) at FormGroupDirective.addControl (forms.js:5699) at FormControlName._setUpControl (forms.js:6274) at FormControlName.ngOnChanges (forms.js:6219) at FormControlName.rememberChangeHistoryAndInvokeOnChangesHook (core.js:1506) at callHook (core.js:2525) at callHooks (core.js:2492) at executeInitAndCheckHooks (core.js:2443) at selectIndexInternal (core.js:8389)
this is my code for question-form-component.html:
<div [formGroup]="form">
<label [attr.for]="question?.key">{{ question?.label }}</label>
<div [ngSwitch]="question?.controlType">
<input
ngDefaultControl
*ngSwitchCase="'textbox'"
[formControlName]="question?.key"
[id]="question?.key"
[type]="question?.type"
[value] = "question?.value"
/>
<div [ngSwitch]="question?.controlType">
<ion-textarea
ngDefaultControl
*ngSwitchCase="'textArea'"
[formControlName]="question?.key"
[id]="question?.key"
autoGrow="question?.autoGrow"
[value]= "question?.value"
></ion-textarea>
</div>
<div *ngSwitchCase="'barcodeScanner'">
<app-barcode-scanner
[formControlName]="question?.key"
(ngModelChange)="question?.onChange($event)"
[id]="question?.key"
[value]="question?.value"
></app-barcode-scanner>
</div>
<div *ngSwitchCase="'datebox'">
<ion-datetime [formControlName]="question?.key" [id]="question?.key">
</ion-datetime>
</div>
<div *ngSwitchCase="'switchBox'">
<p class="switchText">
{{ getValue ? question.labelTrue : question.labelFalse }}
</p>
<ion-icon
[name]="getValue ? question.iconTrue:question.iconFalse"
></ion-icon>
<ion-toggle
[formControlName]="question?.key"
[id]="question?.key"
></ion-toggle>
</div>
<div
[formControlName]="question?.key"
[id]="question?.key"
>
<div *ngSwitchCase="'itemSelector'"
[formControlName]="question?.key"
[id]="question?.key"
ngDefaultControl
>
<app-selector-items
[formControlName]="question?.key"
[id]="question?.key"
[text]="question?.text" [service]="question?.service" (selectedItem)="question.selectedItem($event)"
[sorterFunction]="question?.sorterFunction"
[filterFunction]="question?.ItemsFilterFunction"
[createPopup]= "question?.createPopup"
[item]="question?.value"
(selectedItem)="question.selectedItem($event)" >
</div>
<select
[id]="question?.key"
*ngSwitchCase="'dropdown'"
[value]="question?.value"
[formControlName]="question?.key"
>
<option *ngFor="let opt of question?.options" [value]="opt?.value">{{
opt.key
}}</option>
</select>
<div *ngSwitchCase="'geobox'">
<input-geolocation
[id]="question?.key"
[address]="question.value?.adress"
[formControlName]="question?.key"
(ngModelChange)="question?.onChange($event)"
></input-geolocation>
</div>
{{ question ? question.label : "" }} is required
this is my question-form-component.ts:
import {
Component,
Input,
OnInit,
Output,
EventEmitter,
ChangeDetectionStrategy,
ɵConsole,
OnChanges,
SimpleChanges
} from '#angular/core';
import { FormGroup, FormControl } from '#angular/forms';
import { QuestionBase } from '../../models/question-base';
#Component({
selector: 'app-question',
templateUrl: './question-form-component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class QuestionFormComponent implements OnInit, OnChanges {
public value: any;
#Input() question: QuestionBase;
#Input() form: FormGroup;
ngOnInit() {
this.value = this.question ? this.question.value : undefined;
this.form = this.form
? this.form
: new FormGroup({
// I need an instance of formgroup for run the tests
name: new FormControl(this.question.key),
value: new FormControl(this.question.value)
});
}
ngOnChanges(changes: SimpleChanges) {
}
get isValid() {
return this.question ? this.form.controls[this.question.key].valid : false;
}
get getValue() {
return this.question.key ? this.form.get(this.question.key).value : '';
}
getIcon() {
return this.form.get(this.question.key).value ? String(this.question.iconTrue) : String(this.question.iconFalse)
}
}
thanks in advance

[Vue warn]: Error in mounted hook: "Error: viewType "" is not available. Please make sure you've loaded all neccessary plugins

Im trying to use FullCalendar as a vue component in Laravel. I've loaded the plugins correctly as per the documentation but for whatever reason, they are not loading https://fullcalendar.io/docs/vue
Component:
template>
<div class="container">
<div class="row justify-contnet-center">
<div class="col-lg-8">
<form #submit.prevent>
<div class="form-group">
<label for="event_name">event Name</label>
<input
type="text"
id="event_name"
class="form-control"
v-model="newevent.event_name"
>
</div>
<div class="row">
<div class="cold-lg-8">
<div class="form-group">
<label for="date">Date</label>
<input
type="date"
id="date"
class="form-control"
v-model="newevent.date"
>
</div>
</div>
<div class="row">
<div class="col-lg-8">
<div class="form-group">
<label for="time">Time</label>
<input
type="time"
id="time"
class="form-control"
v-model="newevent.time"
>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-4" v-if="addingMode">
<button class="btn btn-custom" #click="addNewevent">Book event</button>
</div>
<template>
<div class="col-lg-6 mb-4">
<button class="btn btn-success" #click="updateevent">Update</button>
<button class="btn btn-danger" #click="deleteevent">Delete</button>
<button class="btn btn-warning" #click="addingMode = !addingMode">Cancel</button>
</div>
</template>
</form>
</div>
<div class="col-lg-8 full-calendar" id="calendar">
<FullCalendar #eventClick="showevent" defaultView:="dayGridMonth" :plugins="calendarPlugins" :events="events"/>
</div>
</div>
</div>
</template>
<script>
import { Calendar } from '#fullcalendar/core'
import FullCalendar from '#fullcalendar/vue'
import dayGridPlugin from '#fullcalendar/daygrid'
import interactionPlugin from '#fullcalendar/interaction'
import axios from 'axios'
export default {
components:{
FullCalendar // make custom tag avaliable
},
data() {
return {
calendarPlugins: [ dayGridPlugin, interactionPlugin],
events: "",
newevent: {
event_name: "",
date: "",
time: ""
},
addingMode: true,
indexToUpdate: ""
};
},
created() {
this.getevents();
},
methods: {
addNewevent() {
axios.post('/api/event', {
...this.newevent
})
.then(data=> {
this.getevents(); //update list of getevents
this.resetForm();
})
.catch(err =>
// alert("Unable to add event")
console.log(err.response.data)
);
},
showevent(arg) {
console.logt(arg);
this.addingMode = false;
const {id, event, date, time} = this.events.find (
event => event.id === +arg.event.id
);
this.indexToUpdate = id;
this.newevent = {
event_name: event, // comeback to and see if inserts into db as event_name
date: date,
time: time
};
},
updateevent() {
axios.put('/app/event/' + this.indexToUpdate, {
...this.newevent
})
.then(resp => {
this.resetForm();
this.getevents();
this.addingMode = !this.addingMode;
})
.catch(err =>
// alert('Unable to update event!')
console.log(err.response.data)
);
},
deleteevent() {
axios.delete('/api/event/' + this.indexToUpdate)
.then(resp => {
this.resetForm();
this.getevents();
this.addingMode = !this.addingMode;
})
.catch(err =>
// alert('Unable to delete event')
console.log(err.response.data)
);
},
getevents(){
axios.get('/api/event')
.then(resp => (this.events = resp.data.data))
.catch(err => console.log(err.response.data));
},
resetForm() {
Object.keys(this.newevent).forEach(key=> {
return (this.newevent[key] = "");
});
}
},
watch: {
indexToUpdate() {
return this.indexToUpdate
}
}
};
Then also I have initialized the component with es6 as per this part of the doc https://fullcalendar.io/docs/initialize-es6
import { Calendar } from '#fullcalendar/core';
import dayGridPlugin from '#fullcalendar/daygrid';
import interactionPlugin from '#fullcalendar/interaction';
document.addEventListener('DOMContentLoaded', function() {
let calendarEl = document.getElementById('calendar');
let calendar = new Calendar(calendarEl, {
plugins: [ dayGridPlugin , interactionPlugin ]
});
calendar.render();
});
This is my app.js
Vue.component('calendar-component', require('./components/CalendarComponent.vue').default);
<FullCalendar #eventClick="showevent" defaultView:="dayGridMonth" :plugins="calendarPlugins" :events="events"/>
should become
<FullCalendar :options="calendarOptions" />
I saw the FullCalendar code in github and it doesn't support props defaultView and plugins. Instead it uses prop with name "options"
<script>
import FullCalendar from '#fullcalendar/vue'
import dayGridPlugin from '#fullcalendar/daygrid'
import interactionPlugin from '#fullcalendar/interaction'
export default {
components: {
FullCalendar // make the <FullCalendar> tag available
},
data() {
return {
calendarOptions: {
plugins: [ dayGridPlugin, interactionPlugin ],
initialView: 'dayGridMonth'
}
}
}
}
</script>
<template>
<FullCalendar :options="calendarOptions" />
</template>
Please check the plugin documentation

Angular 8 - FormControl Pattern Validation

I am trying to validate the user field with letters only.
Following the documentation at https://angular.io/api/forms/Validators#pattern
I am not getting the expected result.
Validator.required works.
Validator.minLength works.
But the pattern does not.
I need the user field to have only letters.
Already looked for similar issues here in the forum and tried some implementations but it is not working.
I also tried to add direct into the html tag [pattern]='onlyLetters' and also didn't work.
html
<form (ngSubmit)="onSubmitNewUser()" [formGroup]="userFormGroup" >
<mat-card>
<mat-card-title fxLayoutAlign="center">{{'USERS.NEW'|translate}}</mat-card-title>
<mat-card-content fxLayoutAlign="left" fxLayout="column">
<mat-form-field fxFlex="100%">
<mat-label>{{'USERS.GROUP'|translate}}</mat-label>
<mat-select formControlName="group" >
<mat-option *ngFor="let group of groups" value="{{ group.users_group_id }}">{{ group.users_group_name }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="100%">
<input
[pattern]="pattern"
placeholder="{{'USERS.USERNAME'|translate}}"
type="text"
formControlName="username"
matInput />
<mat-error *ngIf="formControlUsername.hasError('required')" >
{{'VALIDATION.REQUIRED'|translate}}
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="250px" hintLabel="{{'VALIDATION.PASSWORD_HINT'|translate}}">
<input
type="password"
placeholder="{{'USERS.PASSWORD'|translate}}"
matInput
formControlName="password"/>
<mat-hint align="end"> {{ formControlPassword.value?.length }} / 6 </mat-hint>
<mat-error>{{'VALIDATION.MIN_LENGTH'|translate}}</mat-error>
</mat-form-field>
</mat-card-content>
<mat-card-actions fxLayoutAlign="left">
<button
type="submit"
color="primary"
mat-raised-button
[disabled]="userFormGroup.invalid">{{'SAVE'|translate}}</button>
</mat-card-actions>
</mat-card>
</form>
TS file
import { Component, OnInit} from '#angular/core';
import { FormControl, FormGroup, Validators} from '#angular/forms';
import { GroupsModel} from '../_models/groups.model';
import { UsersService} from '../_services/users.service';
#Component({
selector: 'app-users-add',
templateUrl: './users-add.component.html',
styleUrls: ['./users-add.component.scss']
})
export class UsersAddComponent implements OnInit {
pattern = "[a-zA-Z]*";
formControlGroup = new FormControl('',{
validators: [Validators.required]
});
formControlUsername = new FormControl('',{
validators: [
Validators.required,
Validators.pattern(this.pattern)
]
});
formControlPassword = new FormControl('',{
validators: [
Validators.required,
Validators.minLength(6)
]
});
userFormGroup: FormGroup;
groups: GroupsModel[] = [];
constructor(private usersService: UsersService) { }
ngOnInit() {
this.userFormGroup = new FormGroup({
group: this.formControlGroup,
username: this.formControlUsername,
password: this.formControlPassword
});
this.usersService.getGroups().subscribe( data => {
this.groups = data
});
}
onSubmitNewUser() {
console.log(this.userFormGroup.value);
}
}

How to validate a form on button submit

I have a form, which is getting validated once the control gets the class change from ng-untouched ng-pristine ng-invalid to ng-pristine ng-invalid ng-touched but if i have a form with more controls then i want the user to know which field he/she has missed out on the button submit. how can i do that using angularJS2. I have used ReactiveFormsModule to validate the controls
The following is my code: component
import { Component } from '#angular/core';
import { FormBuilder, Validators, FormGroup, FormControl } from '#angular/forms';
#Component({
selector: 'page',
templateUrl:'../app/template.html'
})
export class AppComponent {
registrationForm: FormGroup;
constructor(private fb: FormBuilder) {
this.registrationForm = fb.group({
username: ['', [Validators.required, Validators.minLength(4)]],
emailId: ['', [Validators.required, this.emailValidator]],
phonenumber: ['', [Validators.required, this.phoneValidation]]
})
}
emailValidator(control: FormControl): { [key: string]: any } {
var emailRegexp = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+#[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
if (control.value && !emailRegexp.test(control.value)) {
return { invalidEmail: true };
}
}
phoneValidation(control: FormControl) {
if (control['touched'] && control['_value'] != '') {
if (!/^[1-9][0-9]{10}$/.test(control['_value'])) {
return { 'invalidPhone': true }
}
}
}
}
The following is my code: module
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { ReactiveFormsModule } from '#angular/forms';
import { AppComponent } from '../app/component';
#NgModule({
imports: [BrowserModule, ReactiveFormsModule],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
The following is my code: template
<form [formGroup]="registrationForm" (ngSubmit)="registrationForm.valid && submitRegistration(registrationForm.value)">
<input type="text" formControlName="username" placeholder="username" />
<div class='form-text error' *ngIf="registrationForm.controls.username.touched">
<div *ngIf="registrationForm.controls.username.hasError('required')">Username is required.</div>
</div>
<br />
<input type="text" formControlName="emailId" placeholder="emailId" />
<div class='form-text error' *ngIf="registrationForm.controls.emailId.touched">
<div *ngIf="registrationForm.controls.emailId.hasError('required')">email id is required.</div>
<div *ngIf="registrationForm.controls.emailId.hasError('invalidEmail')">
Email is not in correct format.
</div>
</div>
<br />
<input type="text" formControlName="phonenumber" placeholder="phonenumber" />
<div class='form-text error' *ngIf="registrationForm.controls.phonenumber.touched">
<div *ngIf="registrationForm.controls.phonenumber.hasError('required')">phone number is required.</div>
<div *ngIf="registrationForm.controls.phonenumber.hasError('invalidPhone')">Invalid phone number.</div>
</div>
<br />
<input type="submit" value="Submit" />
</form>
I thought of updating all the invalid controls class to ng-untouched ng-pristine ng-invalid but not sure if this is the right approach
Angular forms don't provide ways to specify when to do validation.
Just set a flag to true when the form is submitted and show validation warnings only when the flag is true using *ngIf="flag" or similar.
<form [formGroup]="registrationForm" (ngSubmit)="submitRegistration(registrationForm.value)">
<div *ngIf="showValidation> validation errors here </div>
showValidation:boolean = false;
submitRegistration() {
if(this.registrationForm.status == 'VALID') {
this.processForm();
} else {
this.showValidation = true;
}
}

Angular 2 - Required field validation if checkbox is selected

Hy guys I'm new to Angular2 and in JS frameworks in general. I'm flowing tutorials on official site and haven't been able to find the solution to this problem.
So I have checkbox which is optional but if the checkbox is "checked" a new input field is shown. this part is not a problem. The problem is that I'm using modal based validation and I can't figure out how to make this new input field required only if the checkbox is checked.
this is may implementation so far:
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<!--{{form}}-->
<div formGroupName="test">
<div class="field">
<div class="checkbox">
<input type="checkbox" name="entryRecurring" value="" id="entryRecurring" formControlName="entryRecurring" />
<label for="entryRecurring">
<div class="checkbox_icon"></div>
Recurring Entry
</label>
</div>
</div>
<div *ngIf="form.value.test.entryRecurring">
<div class="field">
<label for="entryRecurringAmount">Repeat Amount</label>
<input type="text" name="entryRecurringAmount" value="" id="entryRecurringAmount" formControlName="entryRecurringAmount" />
</div>
</div>
</div>
<div class="field last">
<button name="submit" id="submit" class="btn btn_sushi" [disabled]="!form.valid">Submit</button>
</div>
import {Component, Input, OnInit, OnChanges} from '#angular/core';
import { Validators } from '#angular/common';
import { REACTIVE_FORM_DIRECTIVES, FormGroup, FormControl, FormBuilder } from '#angular/forms';
import { FormMessages } from './../helpers/formMessages.component';
import {EntriesService} from './entries.service';
import {ValidationService} from '../helpers/validation.service';
import {Category, CategoryByType} from '../../mock/mock-categories';
#Component({
selector: 'entryForm',
templateUrl: 'app/components/entries/entriesEdit.template.html',
directives: [REACTIVE_FORM_DIRECTIVES, FormMessages],
providers: [EntriesService, ValidationService]
})
export class EntriesEditComponent implements OnInit, OnChanges {
#Input() control: FormControl;
public form:FormGroup;
public submitted:boolean = false;
// private selectedId: number;
categories: Category[];
categoriesSortedByType: CategoryByType[];
constructor(
private _fb:FormBuilder,
private _entriesService: EntriesService
// private _router: Router
) {
this.form = this._fb.group({
test: this._fb.group({
entryRecurring: [''],
entryRecurringAmount: [''],
})
});
}
onSubmit() {
this.submitted = true;
// console.log(this.form.value);
if (this.form.dirty && this.form.valid) {
this._entriesService.saveEntry(this.form.value);
}
}
You could do that by using a custom validation service.
import {NgFormModel} from "angular2/common";
import {Component, Host} from 'angular2/core';
#Component({
selector : 'validation-message',
template : `
<span *ngIf="errorMessage !== null">{{errorMessage}}</span>
`,
inputs: ['controlName : field'],
})
export class ControlMessages {
controlName : string;
constructor(#Host() private _formDir : NgFormModel){
}
get errorMessage() : string {
let input = this._formDir.form.find(this.controlName);
let checkBx = this._formDir.form.find('checkBoxName');
if(input.value.trim() === '' && checkBx.checked) {
return 'The input field is now required'
}
return null;
}
}
Then use the new component like bellow
<div *ngIf="form.value.test.entryRecurring">
<div class="field">
<label for="entryRecurringAmount">Repeat Amount</label>
<input type="text" name="entryRecurringAmount" value="" id="entryRecurringAmount" ngControl="entryRecurringAmount" />
<validation-message field="entryRecurringAmount"></validation-message>
</div>
</div>
Hope that helped!

Resources