Nishant Panwar
Nishant Panwar

Reputation: 13

ERROR TypeError: Cannot read property 'title' of null

I want to update data in firebase(realtime database), by passing the table values in update form,but it shows me an error =

ERROR TypeError: Cannot read property 'title' of null

and whenever I try to use [(ngModel)]="product.price" my code show the error

Cannot read property 'price' of null

This is my .ts file

import { Component, OnInit } from '@angular/core';
import { CategoryService } from 'src/app/services/category.service';
import { ProductsService } from 'src/app/services/products.service';
import { Router, ActivatedRoute } from '@angular/router';
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 {

  product: any = {};
  categories$;
  constructor(
    private router: Router,
    private route: ActivatedRoute,
    private categoryService: CategoryService,
    private productService: ProductsService
  ) {
    this.categories$ = categoryService.getCategories();
    let id = this.route.snapshot.paramMap.get('id');
    if (id)
      this.productService.get(id).pipe(take(1)).subscribe(p => this.product = p);

  }
  save(product) {
    this.productService.create(product);
    console.log(product);
    this.router.navigate(['/admin/products']);
  }

  ngOnInit() {
  }

This is my .html file

<mat-grid-list cols="2" rowHeight="86%">
      <mat-grid-tile>
            <form class="example-form" #f="ngForm" (ngSubmit)="save(f.value)">
                  <mat-form-field class="example-full-width" appearance="outline">
                        <mat-label for="title">Product Name</mat-label>
                        <input matInput [(ngModel)]="product.title" name="title" type="text" id="title" required
                              #pname="ngModel">
                        <mat-error *ngIf="pname.touched"></mat-error>
                  </mat-form-field>
                  <mat-form-field class="mywidth" appearance="outline">
                        <mat-label for="price">Product Price</mat-label>
                        <input matInput ngModel name="price" type="number" id="price" #pprice="ngModel" required
                              [min]="0">
                        <mat-error style="color: red;" *ngIf="pprice.touched && pprice.invalid">field required*
                        </mat-error>
                        <span mat-button matSuffix mat-stroked-button aria-label="search">
                              <mat-icon>₹</mat-icon>
                        </span>
                  </mat-form-field>&nbsp;
                  <mat-radio-group ngModel name="subprice" #subprice="ngModel">
                        <mat-radio-button value="kg">/kg</mat-radio-button>&nbsp;
                        <mat-radio-button value="g">/g</mat-radio-button>&nbsp;
                        <mat-radio-button value="liter">/liter</mat-radio-button>
                  </mat-radio-group>
                  <mat-form-field class="example-full-width" appearance="outline">
                        <mat-label>Category</mat-label>
                        <mat-select ngModel name="category" id="category" required #cat="ngModel">
                              <mat-option>None</mat-option>
                              <mat-option *ngFor="let c of categories$ | async" [value]="c.name">{{ c.name }}
                              </mat-option>
                        </mat-select>
                        <mat-error style="color: red;" *ngIf="cat.touched && cat.invalid">field required*</mat-error>
                  </mat-form-field>
                  <mat-form-field class="example-full-width" appearance="outline">
                        <mat-label for="imageUrl">ImageUrl</mat-label>
                        <input matInput type="text" ngModel name="imageUrl" id="imageUrl" #imgUrl="ngModel">
                  </mat-form-field>
                  <button mat-raised-button type="submit" color="warn">Save</button>
            </form>
      </mat-grid-tile>
      <mat-grid-tile>
            <mat-card class="example-card">
                  <mat-card-header>
                        <mat-card-title>{{ pname.value }}</mat-card-title>
                  </mat-card-header>
                  <img mat-card-image [src]="imgUrl.value">
                  <mat-card-content>
                        <p>{{ pprice.value }} / {{ subprice.value }}</p>
                  </mat-card-content>
            </mat-card>

      </mat-grid-tile>
</mat-grid-list>

This is my product.service.ts

 import { Injectable } from '@angular/core';
    import { AngularFireList, AngularFireDatabase } from '@angular/fire/database';
    import { Item } from '../models/product';

    @Injectable({
      providedIn: 'root'
    })
    export class ProductsService {
      constructor(
        private db: AngularFireDatabase
      ) { }

      create(product) {
        return this.db.list('/products').push(product);
      }
      getAll() {
        return this.db.list('/products').valueChanges();
      }
      get(productId) {
        return this.db.object('/products/' + productId).valueChanges();
      }
    }

Upvotes: 0

Views: 2630

Answers (3)

Mr.Llaka
Mr.Llaka

Reputation: 36

There are some steps to be taken: 1. create an interface and declare all input parameters: product.ts

   export interface Product {
      key?: string;
      title: string;
      price: number;
      etc...
}
  1. in product.service.ts:

    getAll() { return this.db.list('/products/') .snapshotChanges() .pipe( map(actions => actions.map(a => ({ key: a.payload.key, ...(a.payload.val() as {}) })) ) ); }

  2. in my.ts, declare d and replace let id and if() as below:

    id; this.id = this.route.snapshot.paramMap.get('id'); if (this.id) this.productService.get(this.id) .subscribe(p => this.product = p);

4.try it

Upvotes: 0

MoxxiManagarm
MoxxiManagarm

Reputation: 9134

You are doing take(1). Not sure but I think the first value of the observable might be undefined. Try takeuntil, but I also recommend to not use subscribe, use async pipe instead

Upvotes: 1

Ponpon32
Ponpon32

Reputation: 2210

this.product is assigned inside the subscription, but when the templates is rendered it's still undefined, you should use the async pipe when accessing observables value inside the template or wrap the used of product.title with ngIf on the product object.

Upvotes: 1

Related Questions