Angular 10 +打字稿
在我的Angular App中,我具有负责编辑配方的组件。
在我的组件上,我有一种方法可以从路线快照中加载食谱
当我到达组件的地址是..recipes / 5 / edit
时在控制台上,我看到以下错误:
Cannot read property 'id' of undefined
但是我可以看到我的配方已加载并显示了属性。
您能给我一个提示吗?
我的代码:
Component.ts
export class RecipeEditComponent implements OnInit {
@ViewChild('editForm', { static: true }) editForm: NgForm;
recipe: IRecipe;
photos: IPhoto[] = [];
uploader: FileUploader;
hasBaseDropZoneOver = false;
baseUrl = environment.apiUrl;
currentMain: IPhoto;
constructor(private route: ActivatedRoute, private recipeService: RecipeService,
private toastr: ToastrService) { }
ngOnInit(): void {
this.loadRecipe();
this.initializeUploader();
}
loadRecipe() {
this.recipeService.getRecipe(this.route.snapshot.params.id).subscribe(recipe => {
this.recipe = recipe;
})
}
public fileOverBase(e: any): void {
this.hasBaseDropZoneOver = e;
}
initializeUploader () {
this.uploader = new FileUploader({
url: this.baseUrl + 'recipes/' + this.recipe.id + '/add-photo',
authToken: 'Bearer ' + localStorage.getItem('token'),
isHTML5: true,
allowedFileType: ['image'],
removeAfterUpload: true,
autoUpload: false,
maxFileSize: 10 * 1024 * 1024
});
this.uploader.onAfterAddingFile = (file) => {
file.withCredentials = false;
}
this.uploader.onSuccessItem = (item, response, status, headers) => {
if (response) {
const photo : IPhoto = JSON.parse(response);
this.recipe.recipePhotos.push(photo);
if (photo.isMain) {
this.recipe.photoUrl = photo.url;
}
}
}
}
updateRecipe(id: number) {
this.recipeService.editRecipe(id, this.recipe).subscribe(next => {
this.toastr.success('Recipe updated successfully');
this.editForm.reset(this.recipe);
}, error => {
this.toastr.error(error);
});
}
setMainPhoto(photo: IPhoto) {
this.recipeService.setMainPhoto(this.recipe.id, photo.id)
.subscribe(() => {
this.currentMain = this.recipe.recipePhotos.filter(p => p.isMain === true)[0];
if (this.currentMain) {
this.currentMain.isMain = false;
photo.isMain = true;
this.toastr.success('Succesfully changed main photo');
}
}, error => {
this.toastr.error(error);
});
}
deletePhoto(id: number) {
this.recipeService.deletePhoto(this.recipe.id, id).subscribe(() => {
this.recipe.recipePhotos.splice(this.recipe.recipePhotos.findIndex(p => p.id === id), 1);
this.toastr.success('Photo has been deleted');
}, error => {
this.toastr.error('Failed to delete the photo');
});
}
}
HTML
<div class="container mt-4 border" *ngIf="recipe">
<h3 class="text-center">Add Photos</h3>
<div class="row">
<div class="col-sm-2" *ngFor="let photo of recipe.recipePhotos">
<img src="{{photo.url}}" class="img-thumbnail p-1" alt="">
<div class="text-center">
<button type="button" class="btn btn-sm mr-1 mb-2"
(click) = "setMainPhoto(photo)"
[disabled]="photo.isMain"
[ngClass] = "photo.isMain ? 'btn-danger active' : 'btn-secondary'"
>Main</button>
<button type="button" class="btn btn-sm btn-danger mb-2"
(click)="deletePhoto(photo.id)" >
<i class="fa fa-trash-o"></i></button>
</div>
</div>
</div>
<div class="row justify-content-md-center mt-5 border">
<div class="col col-sm-4">
<div class="mt-4 text-center">
Multiple
<input type="file" ng2FileSelect [uploader]="uploader" multiple /><br/>
Single
<input type="file" ng2FileSelect [uploader]="uploader" />
</div>
</div>
<div class="col col-sm-6">
<div ng2FileDrop
[ngClass]="{'nv-file-over': hasBaseDropZoneOver}"
(fileOver)="fileOverBase($event)"
[uploader]="uploader"
class="card bg-faded p-3 text-center mt-3 mb-3 my-drop-zone">
<i class="fa fa-upload fa-3x"></i>
Drop Photos Here
</div>
</div>
</div>
<div class="col-md-6 mt-5" style="margin-bottom: 40px" *ngIf="uploader?.queue?.length">
<h3 class="text-center">Upload queue</h3>
<p>Queue length: {{ uploader?.queue?.length }}</p>
<table class="table">
<thead>
<tr>
<th width="50%">Name</th>
<th>Size</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of uploader.queue">
<td><strong>{{ item?.file?.name }}</strong></td>
<td *ngIf="uploader.options.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
<td *ngIf="uploader.options.isHTML5">
</tr>
</tbody>
</table>
<div>
<div>
Queue progress:
<div class="progress mb-4" >
<div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': uploader.progress + '%' }"></div>
</div>
</div>
<button type="button" class="btn btn-success btn-s"
(click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
<span class="fa fa-upload"></span> Upload
</button>
<button type="button" class="btn btn-warning btn-s"
(click)="uploader.cancelAll()" [disabled]="!uploader.isUploading">
<span class="fa fa-ban"></span> Cancel
</button>
<button type="button" class="btn btn-danger btn-s"
(click)="uploader.clearQueue()" [disabled]="!uploader.queue.length">
<span class="fa fa-trash"></span> Remove
</button>
</div>
</div>
<form #editForm="ngForm" id="editForm" (ngSubmit)="updateRecipe(recipe.id)" >
<h5 class=" text-center mt-2">Recipe details:</h5>
<div class="form-group mt-3">
<label for="city">Name</label>
<label for="city">{{recipe.id}}</label>
<input class="form-control" type="text" name="name" [(ngModel)]="recipe.name">
</div>
<div class="form-group">
<label for="country">Ingredients</label>
<input class="form-control" type="text" name="country" [(ngModel)]="recipe.ingredients">
</div>
<h5 class=" text-center mt-4">Description</h5>
<textarea name="description" cols=100% rows="8" class="form-control mt-2"
[(ngModel)]="recipe.description"></textarea>
</form>
<button [disabled]="!editForm.dirty" form="editForm" class="btn btn-success btn-block mb-5 mt-5">Save changes</button>
</div>
答案 0 :(得分:1)
您正在尝试在this.recipe
初始化之前进行访问(loadRecipe
执行异步操作)。
尝试将this.initializeUploader()
的呼叫从ngOnInit()
移动到loadRecipe()
ngOnInit(): void {
this.loadRecipe();
}
loadRecipe() {
this.recipeService.getRecipe(this.route.snapshot.params.id).subscribe(recipe => {
this.recipe = recipe;
this.initializeUploader();
})
}