[英]I have an issue when I want to edit my product list and i am getting this error Cannot read property 'title' of null
I have an issue after my data is stored in db and I want to edit it. 我的数据存储在db中后出现问题,我想对其进行编辑。 It is not showing data and I am getting cannot read property error.
它没有显示数据,我无法读取属性错误。
Html HTML
admin-products.component.html admin-products.component.html
<p>
<a routerLink="/admin/products/new" class="btn btn-primary">New Products</a>
</p>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Price</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of products$ | async">
<td>{{ p.title }}</td>
<td>{{ p.price }}</td>
<td><a [routerLink]="['/admin/products/', p.$key]">Edit</a></td>
</tr>
</tbody>
</table>
product-form.component.html product-form.component.html
If I check error link in console it is showing an error at all input field. 如果我在控制台中检查错误链接,则所有输入字段均显示错误。 I think mostly error may b here ?
我认为大多数错误可能在这里?
<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 is required</div>
<div *ngIf="imageUrl.errors.url">Please enter a vaild 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
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>
</div>
product-form.component.ts 产品表格。组件
import { Component } from '@angular/core';
import { CategoryService } from 'src/app/category.service';
import { ProductService } from 'src/app/product.service';
import { Router, ActivatedRoute } from '@angular/router';
import 'rxjs/add/operator/take';
@Component({
selector: 'app-product-form',
templateUrl: './product-form.component.html',
styleUrls: ['./product-form.component.css']
})
export class ProductFormComponent {
categories$;
product = {};
constructor(
private router: Router,
private route: ActivatedRoute,
private categoryService: CategoryService,
private productService: ProductService
) {
this.categories$ = categoryService.getCategories();
// tslint:disable-next-line:prefer-const
let id = this.route.snapshot.paramMap.get('id');
// tslint:disable-next-line:curly
if (id)
this.productService.get(id).valueChanges().take(1).subscribe(p => (this.product = p));
}
save(product) {
this.productService.create(product);
this.router.navigate(['/admin/products']);
}
}
product-service.ts 产品服务
import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
@Injectable()
export class ProductService {
products$: AngularFireList<any[]>;
constructor(private db: AngularFireDatabase) {
this.products$ = this.db.list('/products');
}
create(product) {
return this.products$.push(product);
}
getAll() {
return this.db.list('/products').valueChanges();
}
get(productId) {
return this.db.object('/products/' + productId);
}
}
I have tried this method by using *ngIf , [ngModel]="product?.title" 我通过使用* ngIf,[ngModel] =“ product?.title”尝试了此方法
<input *ngIf="title">
Have you tried to wrap your form with ng-container ? 您是否尝试过用ng-container包装表格?
product-form.component.ts 产品表格。组件
@Component({
selector: 'app-product-form',
templateUrl: './product-form.component.html',
styleUrls: ['./product-form.component.css']
})
export class ProductFormComponent {
categories$;
product = null;
constructor(
private router: Router,
private route: ActivatedRoute,
private categoryService: CategoryService,
private productService: ProductService
) {
this.categories$ = categoryService.getCategories();
// tslint:disable-next-line:prefer-const
let id = this.route.snapshot.paramMap.get('id');
// tslint:disable-next-line:curly
if (id)
this.productService.get(id).valueChanges().take(1).subscribe(p => (this.product = p));
}
save(product) {
this.productService.create(product);
this.router.navigate(['/admin/products']);
}
}
product-form.component.html product-form.component.html
<div class="row">
<div class="col-md-6">
<ng-container *ngIf="product">
<form #f="ngForm" (ngSubmit)="save(f.value)">
<!-- YOUR CODE -->
</form>
</ng-container>
</div>
</div>
Try this, 尝试这个,
export class ProductFormComponent {
categories$;
product = {
"title": '',
"price": '',
"category": '',
"imageUrl": '',
};
constructor(
private router: Router,
private route: ActivatedRoute,
private categoryService: CategoryService,
private productService: ProductService
) {
this.categories$ = categoryService.getCategories();
// tslint:disable-next-line:prefer-const
let id = this.route.snapshot.paramMap.get('id');
// tslint:disable-next-line:curly
if (id)
this.productService.get(id).valueChanges().take(1).subscribe(p => (this.product = p));
}
save(product) {
this.productService.create(product);
this.router.navigate(['/admin/products']);
}
}
The reason it is failing because 之所以失败,是因为
this.productService.get(id).valueChanges().take(1).subscribe(p => (this.product = p));
the above line will take time to get the response from the firebase, In the meantime, the HTML component will be rendered before that, so it is trying to access product object in the HTML component, since there is no title, price, category, and imageUrl in product object it will cause the error. 上一行需要花费一些时间才能从Firebase获得响应,与此同时,HTML组件将在此之前呈现,因此,由于没有标题,价格,类别,因此它试图访问HTML组件中的产品对象,产品对象中的imageUrl会导致错误。 So assign the empty values, later it is updated once you receive the response
因此,分配空值,稍后在收到响应后将其更新
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.