【问题标题】:ERROR TypeError: Cannot read property 'title' of null Angular/Firebase错误类型错误:无法读取 null Angular/Firebase 的属性“标题”
【发布时间】:2020-12-04 18:13:55
【问题描述】:

我想通过在输入表单中传递值来从 Firebase(实时数据库)获取数据,并且每当我尝试使用 [(ngModel)]="product.title" 时,我的代码都会显示错误

错误类型错误:无法读取 null 的属性“标题”

这是我的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" required [min]="0">
            </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">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.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 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 ml-3">Delete</button>
    </form>
</div>
<div class="col-md-6">
    <div *ngIf="product.title" class="card" style="width: 18rem;">
        <img class="card-img-top" [src]="product.imageUrl" *ngIf="product.imageUrl">
        <div class="card-body">
          <h5 class="card-title">{{ product.title }}</h5>
          <p class="card-text">{{ product.price | currency:'USD': true }}</p>
        </div>
    </div>
</div>

这是我的 product-form.component.ts

import { Product } from './../../models/product';
import { Router, ActivatedRoute } from '@angular/router';
import { ProductService } from './../../product.service';
import { CategoryService } from './../../category.service';
import { Component, OnInit } from '@angular/core';
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 {
  categories$;
  product: Product = {title: '', price: 0, category: '', imageUrl: ''};
  id: string;

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


  save(product) {
    if (this.id) this.productService.update(this.id, product);
    else this.productService.create(product);

    this.router.navigate(['/admin/products']);
  }

  delete() {
    if (!confirm('Are you sure you want to delete this product?')) return; 
    this.productService.delete(this.id);
       
    this.router.navigate(['/admin/products']);
  }

  ngOnInit(): void {
  }
}

这是我的product.service.ts

import { AngularFireDatabase } from '@angular/fire/database';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class ProductService {
  
  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();
  }
  
  update(productId, product) {
    return this.db.object('/products/' + productId).update(product);
  }
  
  delete(productId) {
    return this.db.object('/products/' + productId).remove();
  }
}


这是我的 product.ts

export interface Product {
    title: string;
    price: number;
    category: string;
    imageUrl: string;
  }

浏览器出错:

core.js:4352 ERROR TypeError: Cannot read property 'title' of null

在 ProductFormComponent_Template (product-form.component.html:6)*

我为此失去了神经。请帮忙!!!

【问题讨论】:

  • 感谢您的回答。我发布了一个问题,10分钟后,我找到了解决方案。

标签: angular typescript firebase-realtime-database


【解决方案1】:

从get(productId) 中观察到的似乎是 null,你应该检查一下。您可以通过替换进行快速检查

this.productService.get(this.id).pipe(take(1)).subscribe((p: Product) =&gt; this.product = p);

与

this.productService.get(this.id).pipe(filter(x =&gt; !!x), take(1)).subscribe((p: Product) =&gt; this.product = p);

所以现在 observable 将跳过 null-s。

除此之外,在您的模板中,您应该始终使用 product?.title 而不是 product.title,这样 Angular 就不会抛出任何错误。 (与所有其他嵌套字段相同)

【讨论】:

  • 感谢您的回答。我发布了一个问题,10分钟后,我找到了解决方案。
  • 没问题,如果是,请将答案标记为正确
【解决方案2】:

这是问题的解决方案:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-18
    • 2021-04-14
    • 2019-11-04
    • 2021-12-03
    • 2017-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多