为什么我无法读取未定义的属性“ id”

时间:2020-10-22 11:34:16

标签: angular typescript

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>

1 个答案:

答案 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();
    })
}