Angular 8 - Upload multiple array of images using form builder - javascript

I have a product form with different fields like product name, description etc.. also array of images.
Product Form
product name product description
product purity product commodity
Images (Add)
checkbox 1 Image 1
checkbox 2 Image 2
checkbox 3 Image 3.
....
I can able to save in my database product name and product description and other fields but don't how to upload those images. Because images are created on clicking the add button and it may have one or as many images based on requirement.I have created the form using Form builder. Given my code below.
Template :
<form class="kt-form kt-form--group-seperator-dashed" [formGroup]="mmgForm">
<div class="kt-form__section kt-form__section--first">
<div class="kt-form__group">
<div class="row">
<label class="col-lg-2 col-form-label">Product Name:</label>
<div class="col-lg-4">
<mat-form-field class="example-full-width">
<input formControlName="prod_name" matInput placeholder="Enter product name" [ngClass]="{ 'is-invalid': submitted && mmgForm.controls['prod_name'].errors }">
<div *ngIf="submitted && mmgForm.controls['prod_name'].errors" class="invalid-feedback cls-formErr">
<div *ngIf="mmgForm.controls['prod_name'].errors.required">Product name is required</div>
</div>
</mat-form-field>
</div>
<label class="col-lg-2 col-form-label">Product description:</label>
<div class="col-lg-4">
<mat-form-field class="example-full-width">
<textarea formControlName="prod_description" matInput placeholder="Enter product description" rows="5" [ngClass]="{ 'is-invalid': submitted && mmgForm.controls['prod_description'].errors }"></textarea>
<div *ngIf="submitted && mmgForm.controls['prod_description'].errors" class="invalid-feedback cls-formErr">
<div *ngIf="mmgForm.controls['prod_description'].errors.required">Product description is required</div>
</div>
</mat-form-field>
</div>
</div>
</div>
<div class="product_images">
<div class="imageHeading">
<p>
Images (<button mat-icon-button color="primary" matTooltip="Add product" (click) = addImage()><mat-icon>add_circle</mat-icon></button>)
</p>
</div>
<div class="kt-form__group">
<div class="row">
<div class="col-lg-1 imageLabel">#</div>
<div class="col-lg-2 imageLabel">Main Image</div>
<div class="col-lg-3 imageLabel">Choose Image</div>
<div class="col-lg-2 imageLabel">Image</div>
<div class="col-lg-2 imageLabel">Actions</div>
</div>
</div>
<div class="imagesContainer">
<div class="kt-form__group image-container container-1" *ngFor="let image of images; index as i">
<div class="row">
<div class="col-lg-1">{{ i+1 }}</div>
<div class="col-lg-2"><input type="checkbox" /></div>
<div class="col-lg-3"><input type="file" accept="image/*" (change)="imagePreview($event, image)" /></div>
<div class="col-lg-2"><img [src]="image.url.imgUrl" class="prod_image" /></div>
<div class="col-lg-2">
<button mat-icon-button color="warn" matTooltip="Delete Product" type="button" (click)="deleteImage(i)">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
Ts File :
// Angular
import { Component, OnInit, ElementRef, ViewChild, ChangeDetectionStrategy, OnDestroy, ChangeDetectorRef } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
// Material
import { SelectionModel } from '#angular/cdk/collections';
import { MatPaginator, MatSort, MatSnackBar, MatDialog, MatRadioButton } from '#angular/material';
import { ProductManagementService } from '../../../../../core/e-commerce/_services/product-management.service';
import { ToastrService } from 'ngx-toastr';
#Component({
selector: 'kt-product-edit',
templateUrl: './product-edit.component.html',
styleUrls: ['./product-edit.component.scss'],
})
export class ProductEditComponent implements OnInit {
mmgForm : any;
fileData: File = null;
previewUrl : any = "/assets/media/images/noimage.jpg";
images : any = [];
constructor(
private products: ProductManagementService,
private router: Router,
private route: ActivatedRoute,
private toastr: ToastrService,
private cdr: ChangeDetectorRef,
private FB: FormBuilder,
) {
}
ngOnInit() {
this.createForm();
this.addImage();
}
createForm() {
this.mmgForm = this.FB.group({
prod_name: ['', Validators.required],
prod_description: ['', Validators.required]
});
}
/**
* Form Submit
*/
submit() {
if (this.mmgForm.invalid) {
console.log(this.mmgForm);
return;
}
const controls = this.mmgForm.controls;
var form_values = {
prod_name: controls.prod_name.value,
prod_description: controls.prod_description.value,
}
this.products
.createProduct(JSON.stringify(form_values)).subscribe( //Calling Service
(data) => {
console.log(data);
},
error => {
}
);
}
imagePreview(fileInput: any, image) {
this.fileData = <File>fileInput.target.files[0];
// Show preview
var mimeType = this.fileData.type;
if (mimeType.match(/image\/*/) == null) {
return;
}
var reader = new FileReader();
reader.readAsDataURL(this.fileData);
reader.onload = (_event) => {
image.url.imgUrl = reader.result;
this.cdr.markForCheck();
}
}
addImage(){
let url = {imgUrl : this.previewUrl}
this.images.push({url});
}
deleteImage(index: number) {
this.images.splice(index, 1)
}
}

I would suggest to create a FileUploadService for that.
The Service method:
uploadFiles(Array<File> files): Observable<FileUploadResponse> {
const url = `your-upload-url`;
const formData: FormData = new FormData();
for(File file in files) {
formData.append('file', file, file.name);
}
return this.http.post<FileUploadResponse>(url, formData /*{headers if necessary}*/);
}
Your component.ts:
//[..]
Array<File> files = [];
onFileInputEvent(event: any) {
for(let i = 0; i < event.srcElement.files.length; i++) {
this.fileName = event.srcElement.files[0].name;
this.files.push(event.srcElement.files[0]);
}
}
uploadFiles(){
this.fileUploadService.uploadFile(this.file).subscribe(res => { // do something}, err =>{});
}
Your component.html:
<!-- [..] -->
<input id="fileInput" placeholder="Images" type="file" (change)="onFileInputEvent($event)" accept=".jpg">
Edit with a more beautiful input
<div class="file-input">
<input id="fileInput" placeholder="CSV-Datei" type="file" class="hidden" (change)="onFileInputEvent($event)" accept=".csv">
<label for="fileInput" class="mat-raised-button">Add images</label>
<mat-chip-list *ngIf="fileName">
<mat-chip [removable]="true" (removed)="remove()">
{{fileName}}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
</mat-chip-list>

Related

How to fix ngModel cannot be used to register form controls with a parent formGroup directive?

I am currently developing an angular application with a django backend, I use ngModel to retrieve lists in selects which allow me to filter a list of checkboxes, however I want to insert in my Reactiveforms the identifier of the selected gears, and i have conflicts between some ngmodels and my Reactiveform doesn't quite understand why And when i add the formArrayName i don't have my select list anymore either, i wonder if it's also a conflict with ngmodel do you have any thoughts on this?
I however used the method [ngModelOptions]="{standalone: ​​true}"
[console error][1]
[1]: https://i.stack.imgur.com/FtQAw.png
HTML
<form [formGroup]="form" (ngSubmit)="submitForm()">
<label for="name">Nom de la flotte à créer</label>
<input class="Nflotte" formControlName="name" type="text" #flotteName placeholder="Nom de la flotte" required>
<div class="wrapper">
<div class="one">
<wcs-select [(ngModel)]="SelectedSerie" name="SelectedSerie" [ngModelOptions]="{standalone: true}" placeholder="Série" id="leselectg" (ngModelChange)="getEnginBySeries()">
<wcs-select-option *ngFor="let serie of series" [value]="serie">{{
serie.code_serie_materiel }}</wcs-select-option>
</wcs-select>
<wcs-select [(ngModel)]="SelectedSousSerie" [ngModelOptions]="{standalone: true}" placeholder="Sous-série" id="leselectg" (ngModelChange)="getEnginBySousSeries()">
<wcs-select-option *ngFor="let sousSerie of SelectedSerie?.sousseries" [value]="sousSerie">{{
sousSerie.code_serie_materiel }}</wcs-select-option>
</wcs-select>
<wcs-select [(ngModel)]="SelectedVariante" [ngModelOptions]="{standalone: true}" placeholder="Variantes" id="leselectg" (ngModelChange)="getEnginByVariante()">
<wcs-select-option *ngFor="let variante of SelectedSousSerie?.variantes">
{{ variante.code_serie_materiel }}
</wcs-select-option>
</wcs-select>
</div>
<div class="two">
</div>
<div class="three">
</div>
</div>
<div class="wrapper">
<div class="fsearch one">
<div class="wrap">
<div class="search">
<input type="text" class="searchTerm" id="search-text" aria-describedby="search-text"
[(ngModel)]="searchText" placeholder="Rechercher un engin" [value]="">
<button type="submit" class="searchButton">
<i class="material-icons">search</i>
</button>
</div>
</div>
</div>
<div class="two"></div>
<div class=" three">
</div>
</div>
<div class="wrapper">
<div class="one">
<form novalidate>
<table class="blueTable" formArrayName="engins">
<thead>
<tr>
<th>Sélectionner tout les engins</th>
<th >num_facade</th>
<th >num_immatriculation_ef</th>
</tr>
</thead>
<tbody style="margin: 15px;" >
<input type="checkbox" [(ngModel)]="masterSelected" [ngModelOptions]="{standalone: true}" name="list_name" value="m1"
(change)="checkUncheckAll()"/>
<tr class="list-group" [formControlName]="i" style="list-style-type: none;" *ngFor="let engin of form.controls?.engins?.controls | appFilter: searchText; let i = index" >
<input type="checkbox" [(ngModel)]="engin.isSelected" name="list_engins[]" formControlName="checked" value="{{engin[i].identifiant}}"
(change)="isAllSelected()"/>
<td>{{engin.num_facade}}</td>
<td>{{engin.num_immatriculation_ef}}</td>
</tr>
</tbody>
</table>
</form>
</div>
</form>
Component.ts
import { Component, OnInit, Input, Pipe, PipeTransform } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { FlotteService } from 'src/app/services/flotte.service';
import { ApiService } from 'src/app/services/api.service';
import { Engins, SerieBase, SousSerieEngin, VariantesEngin } from 'src/app/interface/serie';
import { SerieEngin } from 'src/app/interface/serie';
import { Flotte } from 'src/app/interface/flotte';
import { VisualisationComponent } from '../visualisation/visualisation.component';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { environment } from 'src/environments/environment';
import { Emitters } from 'src/app/emitters/emitters';
import { NgForm } from '#angular/forms';
import { FormBuilder } from '#angular/forms';
import { FormGroup, Validators, FormControl, FormArray } from '#angular/forms';
export class FlotteComponent implements OnInit {
message: any;
error: any;
SelectedSerie?: SerieEngin;
SelectedSousSerie?: SousSerieEngin;
SelectedVariante?: VariantesEngin;
SelectedFlotte?: Flotte;
SelectionSerie: String = '';
ngOnInit(): void {
this.http.get('http://localhost:8000/api/user', {withCredentials: true}).subscribe(
(res: any) => {
this.message = `Bonjour ${res.username}`;
Emitters.authEmitter.emit(true);
},
);
this.getAllFlottes()
this.flotteservice.getSeries2()
.subscribe(response => {
this.series = response;
}
)
this.engins.forEach(engin => {
if (engin.value) {
engin.value.forEach((checkbox: any) => {
})
}
})
this.engins = [];
this.form = new FormGroup({
// control for radio exemple
name: new FormControl(null, Validators.required),
// control for Checkbox exemple
engins: new FormArray([]),
calculateur: new FormControl(null, Validators.required),
type_fichier: new FormControl(null, Validators.required),
});
// bind existing value to form control
this._patchValues();
}
private _patchValues(): void {
// get array control
const formArray = this.form.get('engins') as FormArray;
// loop for each existing value
this.engins.forEach((engin) => {
// add new control to FormArray
formArray.push(
// here the new FormControl with item value from RADIO_LIST_FROM_DATABASE
new FormGroup({
fengins: new FormControl(engin.identifiant),
checked: new FormControl(engin.checked),
})
);
});
}
submitForm(): void {
const { value } = this.form;
// get selected fruit from FormGroup value
const selectedEngin =
value?.engins?.filter((f: Engins) => f.checked) || [];
// form value binded
console.log('current form value: ', value);
console.log('only selected form value: ', selectedEngin);
// original value from database not change
console.log('original engins list: ', this.engins);
this.result = {
name: value?.name || '',
selectedEngin,
calculateur: value?.calculateur || '',
type_fichier: value?.type_fichier|| '',
}
this.api.registerFlotte(this.form.value)
.subscribe((res:any)=>{console.log(res)});
}
}

Pass input text value to function per click

I want to insert the value inserted into an input in the database using Angular as the frontend and php as the backend but I'm not able to insert the input value into the method along with the user.id.
The input is for the reason of moderation when clicking on disapprove it is necessary to pass the reason but it is not entering.
import { Component, OnInit, TemplateRef } from '#angular/core';
import { FormGroup } from '#angular/forms';
import { observerMixin } from '#rodrigowba/observer-component';
import { ResponseData, DefaultResponse } from '#rodrigowba/http-common';
import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
import { ToastrService } from 'ngx-toastr';
import { Observable } from 'rxjs';
import { ActionPayload } from '~/ngrx';
import {
HotsiteUser,
HotsiteUsersFacade,
HotsiteUsersFormService,
RegistrationStatusTypes,
UpdateHotsiteUserRequest,
HotsitePointsPrebase,
} from '~/admin/users';
import {
updateHotsiteUser,
hotsiteUserUpdated,
hotsiteUserUpdateFailed,
hotsiteUserRegistrationModerated,
hotsiteUserModerateRegistrationFailed
} from '~/admin/users/state';
import { distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators';
#Component({
templateUrl: './view.component.html',
})
export class ViewComponent extends observerMixin() implements OnInit {
user$: Observable<HotsiteUser>;
pointsPrebase$: Observable<HotsitePointsPrebase[]>;
customFields$: Observable<{
field: string,
value: string
}[]>;
registrationStatusTypes = RegistrationStatusTypes;
form: FormGroup;
modalRef: BsModalRef;
submiting = false;
constructor(
private hotsiteUsersFacade: HotsiteUsersFacade,
private hotsiteUsersFormService: HotsiteUsersFormService,
private modalService: BsModalService,
private toastr: ToastrService
) {
super();
this.form = this.hotsiteUsersFormService.updateForm();
}
ngOnInit() {
this.user$ = this.hotsiteUsersFacade.selectCurrentHotsiteUser();
this.customFields$ = this.user$.pipe(
map(user => Object.values(user.custom_fields)),
map(customFields => customFields.map(customField => {
let value = customField.value;
if (Array.isArray(value)) {
value = value.join(', ');
}
return {
field: customField.field,
value
};
}))
);
this.pointsPrebase$ = this.user$.pipe(
map(user => user.id),
distinctUntilChanged(),
tap(id => {
this.hotsiteUsersFacade.fetchHotsitePointsPrebase(id);
}),
switchMap(id => this.hotsiteUsersFacade.selectHotsitePointsPrebaseByHotsiteUser(id))
);
this.observe(this.user$).subscribe(user => {
this.form.patchValue(user);
});
this.observe(
this.hotsiteUsersFacade.ofType(updateHotsiteUser)
).subscribe(() => {
this.submiting = true;
});
this.observe(
this.hotsiteUsersFacade.ofType<ActionPayload<ResponseData<HotsiteUser>>>(
hotsiteUserUpdated,
hotsiteUserRegistrationModerated
)
).subscribe(action => {
const { message, data } = action.payload;
this.submiting = false;
this.toastr.success(message);
});
this.observe(
this.hotsiteUsersFacade.ofType<ActionPayload<DefaultResponse>>(
hotsiteUserUpdateFailed,
hotsiteUserModerateRegistrationFailed
)
).subscribe(action => {
const { message } = action.payload;
this.submiting = false;
this.toastr.error(message);
});
}
onSubmit(id: string, data: UpdateHotsiteUserRequest) {
this.hotsiteUsersFacade.updateHotsiteUser(id, data);
}
openModal(template: TemplateRef<any>, size = 'modal-md') {
this.modalRef = this.modalService.show(template, { class: size });
}
approveRegistration(id: string,reason: string) {
this.hotsiteUsersFacade.moderateRegistrationHotsiteUser(id, { approved: true,reason });
}
rejectRegistration(id: string,reason: string) {
this.hotsiteUsersFacade.moderateRegistrationHotsiteUser(id, { approved: false,reason });
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<form [formGroup]="form" (ngSubmit)="onSubmit(user.id, form.value)" >
<form [formGroup]="form" (ngSubmit)="onSubmit(user.id, form.value)" >
<div class="row mb-3">
<div class="col-12">
<div class="form-group">
<label>Name</label>
<input type="text" [value]="user.name" class="form-control" readonly />
</div>
</div>
<div class="col-12 col-lg-6">
<div class="form-group">
<label>E-mail</label>
<input type="text" [value]="user.email" class="form-control" readonly />
</div>
</div>
<div class="col-12 col-lg-6">
<div class="form-group">
<label>Document</label>
<input type="text" [value]="user.document" class="form-control" readonly />
</div>
</div>
<div class="col-12" *ngFor="let customField of customFields$ | async">
<div class="form-group">
<label>{{ customField.field }}</label>
<input type="text" [value]="customField.value" class="form-control" readonly />
</div>
</div>
<div class="col-auto">
<div class="form-group">
<mat-slide-toggle formControlName="admin" color="primary" ></mat-slide-toggle>
<label class="ml-2">Admin</label>
</div>
</div>
<div class="col-auto">
<div class="form-group">
<mat-slide-toggle formControlName="active" color="primary" ></mat-slide-toggle>
<label class="ml-2">Active</label>
</div>
</div>
</div>
<ng-container *ngIf="pointsPrebase$ | async as pointsPrebase">
<div class="row mb-3" *ngIf="pointsPrebase.length > 0">
<div class="col-12">
<h4 class="font-16 font-weight-bold">Points</h4>
</div>
<div class="col-12 col-lg-6">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>Chave</th>
<th class="text-center">Points</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let points of pointsPrebase">
<td>{{ points.value }}</td>
<td class="text-center">{{ points.points }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</ng-container>
<div class="form-row">
<ng-container *ngIf="user.registration_status === registrationStatusTypes.AwaitingModeration">
<div class="col-auto">
<label>Reason</label>
<input type="text" name="reason" placeholder="Reason of moderation..." class="form-control"/>
</div>
<div class="col-auto">
<button
type="button"
class="btn btn-success"
(click)="approveRegistration(user.id,form.reason)"
>
<app-loading-label [loading]="submiting">Approved </app-loading-label>
</button>
</div>
<div class="col-auto">
<button
type="button"
class="btn btn-danger"
(click)="rejectRegistration(user.id,form.reason)"
>
<app-loading-label [loading]="submiting">Repproved </app-loading-label>
</button>
</div>
</ng-container>
<div class="col text-right">
<button
type="submit"
class="btn btn-orange"
[disabled]="form.invalid || submiting"
>
<app-loading-label [loading]="submiting">Salvar</app-loading-label>
</button>
</div>
</div>
</form>
Error:
Property 'reason' does not exist on type 'formGroup'
As user776686 suggested, there is a formControlName missing linked to "reason" field.
To get the field value in HTML you should access to the FormGroup controls:
(click)="approveRegistration(user.id, form.controls.reason.value)"
Also you can create a "get" property in TS code and then access to it in HTML:
get reason() {
return this.form.controls.reason.value;
}
(click)="approveRegistration(user.id, reason)"
BTW, a field can be accessed too through the "get" method of a FormGroup:
get reason() {
return this.form.get('reason').value;
}
It expects a control with the attribute formControlName="reason" which is not present here:
<input type="text" name="reason" placeholder="Reason of moderation..." class="form-control"/>
This might be a reason.
If that doesn't help, you my also want to look into the *ngIf condition here:
<ng-container *ngIf="user.registration_status === registrationStatusTypes.AwaitingModeration">

How can i validade a button click through an array of inputs?

I have an array of inputs:
<div id="playerZone" *ngFor="let player of team;let i=index">
<div id="buttonZone">
<div class="buttonsAdd">
<mat-form-field appearance="outline" #f="ngForm">
<mat-label>Summoner Name</mat-label>
<label>
<input matInput placeholder="Placeholder"
(change)="updatePlayerSumonerName($event,i)">
</label>
</mat-form-field>
</div>
</div>
<button mat-raised-button routerLink="/waiting" [disabled]="" (click)="placeOnTheList()" hidden="">Waiting Room</button>
And a button that i only want to enable if all inputs are filled, and i dont know how to do that.
I need some guidance.
I could create variables that get to true when the input is written, but i know that is a better way of do that
updatePlayerSumonerName(name,i){
console.log(name.target.value);
this.team[i].summonerName = name.target.value;
}
You can achieve ur requirement as below.
Please check this Demo
in your app.component.ts,
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup, FormArray, Validators, FormBuilder } from '#angular/forms';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
players = [
'player1',
'player2',
'player3',
'player4'
];
constructor(private fb: FormBuilder) { }
form = this.fb.group({
team: new FormArray([])
});
ngOnInit() {
this.addPlayers(this.players);
}
get team(): FormArray {
return this.form.get('team') as FormArray;
}
onFormSubmit(): void {
for (let i = 0; i < this.team.length; i++) {
console.log(this.team.at(i).value);
}
}
addPlayers(players: string[]): void {
players.forEach(player => {
this.team.push(new FormControl(player, [Validators.required]));
});
}
}
and app.component.html,
<div class="container">
<br>
<form [formGroup]="form" (ngSubmit)="onFormSubmit()">
<div formArrayName="team">
<div class="form-group row">
<label for="commessa" class="col-sm-2 col-form-label">Team</label>
<div class="col-sm-10">
<ng-container *ngFor="let player of team.controls; index as idx">
<div class="row">
<div class="col-sm-8">
<input type="text" [ngClass]="{'error':player.invalid && player.touched}"
[formControlName]="idx" class="form-control" id="commessa">
</div>
</div>
</ng-container>
</div>
</div>
</div>
<div>
<button type="submit" class="btn btn-primary" [disabled]="form.invalid">Save</button>
</div>
</form>
</div>

How to display recieved form input data to other component in Angular 6?

register.component.html (the form input component)
<div class="card-content">
<form #registerForm="ngForm" (ngSubmit)="onSubmit(Name.value, Email.value)">
<div class="row">
<div class="input-field col s12">
<i class="material-icons prefix">account_circle</i>
<input type="text" name="Name"
#Name
ngModel required>
<label for="Name">Name</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<i class="material-icons prefix">mail_outline</i>
<input type="text" name="Email"
#Email
ngModel
required
[pattern]="emailPattern">
<label for="Email">Email</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<button class="btn-large btn-submit"
type="submit"
[disabled]='!registerForm.valid'>Start</button>
</div>
</div>
</form>
</div>
register.component.ts
........................................................................................
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { QuizService } from '../shared/quiz.service';
#Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.scss']
})
export class RegisterComponent implements OnInit {
emailPattern = '^[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,4}$';
constructor(private route: Router, private quiz: QuizService) { }
user = {
username: '',
email: ''
};
ngOnInit() {
}
onSubmit(name, email) {
this.user.username = name;
this.user.email = email;
this.route.navigate(['quiz']);
console.log(this.user.username, this.user.email); // log works!!
}
}
quiz.component.html (here i want to display the data which user entered in register component)
.........................................................
<div class="row">
<div class="col s6 offset-s3">
<h3>Welcome to quiz</h3>
<b>Your Name is: </b>
<br>
<b>Your Email is: </b>
</div>
</div>
this.route.navigate(['quiz',{username:username,...}])
and in your quiz component receive data
this.route.params.subscribe(params=>{ console.log(params.username)})
don't forget inject the ActivatedRoute in your quiz
constructor(private route:ActivatedRoute)
There are many way to accomplish this but I would suggest looking at NgRX Store, if you want a simpler solution then you can use a service:
#Injectable({
provideIn: ‘root’
})
export class SomeService {
userSubject = new BehaviorSubject<User>({});
user$: Observable<User> = this.userSubject;
}
In your RegisterComponent submit event you will call someService.userSubject.next(this.user); and in your QuizComponent subscribe to someService.user$ to pick up the data

ERROR TypeError: Cannot read property 'title' of undefined

I've been battling with these block of codes for some days, and even when i try initializing it as an object i get errors.
this is my restaurantForm.ts file
import { Component, OnInit } from '#angular/core';
import {RestaurantService} from '../../restaurant.service';
import {ProductService} from '../../product.service';
import {ActivatedRoute, Router} from '#angular/router';
import 'rxjs/add/operator/take';
import {Product} from '../../model/product';
#Component({
selector: 'app-product-form',
templateUrl: './restaurant-form.component.html',
styleUrls: ['./restaurant-form.component.css']
})
export class RestaurantFormComponent implements OnInit {
restaurants$;
id;
product: Product;
constructor(private restaurantService: RestaurantService,
private productService: ProductService,
private route: ActivatedRoute,
private router: Router) {
this.restaurants$ = this.restaurantService.getAll();
this.id = this.route.snapshot.paramMap.get('id');
if (this.id) {
this.productService.get(this.id).take(1).subscribe(p => this.product = p);
}
this.product = new Product();
}
save(product) {
if (this.id) {
this.productService.update(this.id, product);
} else {
this.productService.create(product);
}
this.router.navigate(['/admin/restaurants']);
}
delete() {
if (!confirm('Are you sure you want to delete this product?')) { return ; }
this.productService.delete(this.id);
this.router.navigate(['/admin/restaurants']);
}
ngOnInit() {
}
}
this is my product model
export interface Product {
$key: string;
title: string;
price: number;
restaurant: string;
imageUrl: string;
}
My restaurantForm.html
<div class="container">
<div class="row">
<div class="col-md-6">
<form #f="ngForm" (ngSubmit)="save(f)">
<div class="form-group">
<label for="title">Title</label>
<input #title="ngModel" [(ngModel)]="product.title" name="title" id="title" type="text" class="form-control" required>
<div class="alert-danger alert" *ngIf="title.touched && title.invalid">
Title is required.
</div>
</div>
<div class="form-group">
<label for="price">Delivery Price</label>
<div class="input-group">
<span class="input-group-addon">₦</span>
<input #price="ngModel" [(ngModel)]="product.price" name="price" id="price"
type="number" class="form-control" required [min]="0">
</div>
<div class="alert alert-danger" *ngIf="price.touched && price.invalid">
<div *ngIf="price.errors.required">
Delivery Price is required
</div>
<div *ngIf="price.errors.min">
Delivery Price should be 0 or higher.
</div>
</div>
</div>
<div class="form-group">
<label for="restaurant">Restaurant</label>
<select #restaurant="ngModel" [(ngModel)]="product.restaurant" name="restaurant" id="restaurant" class="form-control" required>
<option value=""></option>
<option *ngFor="let r of restaurants$ | async" [value]="r.$key">
{{ r.name }}
</option>
</select>
<div class="alert alert-danger" *ngIf="restaurant.touched && restaurant.invalid">
Please select a restaurant.
</div>
</div>
<div class="form-group">
<label for="imageUrl">Image Url</label>
<input #imageUrl="ngModel" [(ngModel)]="product.imageUrl" name="imageUrl"
id="imageUrl" type="text" class="form-control" required url>
<div class="alert alert-danger" *ngIf="imageUrl.touched && imageUrl.invalid">
<div *ngIf="imageUrl.errors.required">Image Url is required.</div>
<div *ngIf="imageUrl.errors.url">Please enter a valid Url.</div>
</div>
</div>
<button class="btn btn-primary">Save</button>
<button type="button" (click)="delete()" class="btn btn-danger">Delete</button>
</form>
</div>
<div class="col-md-6">
<app-product-card [product]="product" [showActions]="false"></app-product-card>
</div>
</div>
</div>
I get the same errors with price, $key, restaurant and imageUrl.
thanks in advance. Although Ive looked up some solutions saying i should use elvis Operator e.g 'product?.title' this method isnt still working.
Because product is undefined, you need to declare and initialize it with empty object inside the constructor or ngOninit.
EDIT:
You need to have the Product declared in the component as,
const product : Produce = { $key: "", title: "",price:0,restuarant :"" ,imageurl:"" };
When the template get initialized, the product is undefined and it continues until the response return from API. Add a check for the template where you bind the object properties.Do the same for price etc.
<input *ngIf="product.title" #title="ngModel" [(ngModel)]="product.title" name="title" id="title" type="text" class="form-control" required>

Categories