Hi everone
I am getting this error
the add new-product page is not working
// product-form.component.ts
import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { CategoryService } from 'src/app/category.service';
import { Product } from 'src/app/models/product';
import { ProductService } from 'src/app/product.service';
import { tap } from 'rxjs/operators';
import { Observable, Subscription } from 'rxjs';
import { AngularFireList } from 'angularfire2/database';
import { take } from 'rxjs/operators';
@Component({
selector: 'app-product-form',
templateUrl: './product-form.component.html',
styleUrls: ['./product-form.component.css']
})
export class ProductFormComponent implements OnInit, OnDestroy {
categories$!: { title: string; }[] | any;
categories!: { title: string; }[] | any;
subscription!: Subscription;
subscription$!: Subscription;
product: any;
id;
//product = {};
constructor(
private router: Router,
private route: ActivatedRoute,
private categoryService: CategoryService,
private productService: ProductService) {
/*
this.subscription = this.categoryService.getCategories().subscribe( categories => {
this.categories = categories;
}); */
this.categories$ = categoryService.getCategories();
//this.categories$ = this.categoryService.getCategoriesValueChanges();
/*this.subscription$ = this.categoryService.getCategoriesValueChanges().subscribe( categories => {
this.categories$ = categories;
}); */
//this.categories$ = this.categoryService.getCategoriesValueChanges();
this.id = this.route.snapshot.paramMap.get('id');
if(this.id) this.productService.get(this.id).pipe(take(1)).subscribe(p => this.product = p );
} // no need to add the private access modifier as we are not going to reference this anywhere outsde the constructor
save(product: Product){ // I added HTMLInputElement from my own
console.log(product);
if(this.id) this.productService.update(this.id, product);
else this.productService.create(product);
this.router.navigate(['/admin/products']);
}
ngOnInit(): void {
this.categories = this.categoryService.getCategories()
.pipe(tap(c => console.log("category =", c)));
}
ngOnDestroy() {
//this.subscription.unsubscribe();
//this.subscription$.unsubscribe();
}
}
// product-form.component.html
<div class="row">
<div class="col-md-6">
<form #f="ngForm" (ngSubmit)="save(f.value)">
<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 alert-danger" *ngIf="title.touched && title.invalid">Title is required</div>
</div>
<div class="form-group">
<label for="price">Price</label>
<div class="input-group-prepend">
<span class="input-group-text">$</span>
<input #price="ngModel" [(ngModel)]="product.price" name="price" id="price" type="number" class="form-control" [min]="0" required>
</div>
<div class="alert alert-danger" *ngIf="price.touched && price.invalid">
<div *ngIf="price.errors.required">Price is required</div>
<div *ngIf="price.errors.min">Minimun Price should be 0 or higher</div>
</div>
</div>
<div class="form-group">
<label for="category">Category</label>
<select #category="ngModel" [(ngModel)]="product.category" name="category" id="category" class="form-control" required>
<option value=""></option>
<option *ngFor="let c of categories$ | async" [value]="c.key">{{c.data.name}}</option>
</select>
<div class="alert alert-danger" *ngIf="category.touched && category.invalid">Category is required</div>
</div>
<div class="form-group">
<label for="imageUrl">Image</label>
<input #imageUrl="ngModel" [(ngModel)]="product.imageUrl" name="imageUrl" id="imageUrl" type="text" class="form-control" url required>
<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>
</form>
</div>
<div class="col-md-6">
<div class="card" style="width: 18rem;">
<img [src]="product.imageUrl" class="card-img-top">
<div class="card-body">
<h5 class="card-title">{{product.title}}</h5>
<p class="card-text">{{product.price | currency:'USD':true }}</p>
</div>
</div>
</div>
</div>
here is the service file
// product.service
import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
import { map } from 'rxjs/operators';
import { Product } from './models/product';
@Injectable({
providedIn: 'root'
})
export class ProductService {
product!: Product;
constructor(private db: AngularFireDatabase) { }
create(product: Product){
this.db.list('/products').push(product);
}
getAll() {
return this.db.list('/products').snapshotChanges().pipe(map(actions => {
return actions.map(a => {
const key = a.payload.key;
const data = a.payload.val();
return {data, key};
})
}));
}
get(productId: string) {
return this.db.object('/products/' + productId).valueChanges();
}
update(productId: string, product: Product){
return this.db.object('/products/' + productId).update(product);
}
}