Невозможно прочитать свойство 'params' со значением NULL при доступе к параметрам родительского маршрута - PullRequest
0 голосов
/ 21 мая 2018

У меня есть такая иерархия в моих маршрутах:

import { Routes } from '@angular/router';

import { AuthenticatedUserComponent } from './authenticated-user/authenticated-user.component';

import { DashboardComponent } from './dashboard/dashboard.component';
import { BookListComponent } from './book-list/book-list.component';
import { BooksByCategoryComponent } from './books-by-category/books-by-category.component';
import { BookDetailComponent } from './book-detail/book-detail.component';
import { BookDetailUserComponent } from './bookdetail-user/bookdetail-user.component';
import { BookMaintComponent } from './book-maint/book-maint.component';
import { ReviewDialogComponent } from './review-dialog/review-dialog.component';
import { SignInComponent } from '../fw/users/sign-in/sign-in.component';
import { RegisterUserComponent } from '../fw/users/register-user/register-user.component';
import { AuthGuard } from './services/auth-guard.service';
import { IsAdminGuard } from './services/is-admin-guard.service';

export const appRoutes: Routes = [  
 { path: 'signin', component: SignInComponent },
 { path: 'register', component: RegisterUserComponent },
 { path: 'authenticated', component: AuthenticatedUserComponent, canActivate: [AuthGuard],
children: [
  { path: '', canActivateChild: [AuthGuard], 
    children: [
      { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
      { path: 'dashboard', component: DashboardComponent },
      { path: 'book-list/:count', component: BookListComponent },
      { path: 'book-detail/:id/:operation', component: BookDetailComponent, canActivate: [IsAdminGuard] },
      {
        path: 'bookdetail-user/:id', component: BookDetailUserComponent,
        children: [
          { path: 'review-dialog/:id', component: ReviewDialogComponent }
        ]
      },
      { path: 'books-by-category/:categoryId', component: BooksByCategoryComponent },
      { path: 'book-maint', component: BookMaintComponent, canActivate: [IsAdminGuard] },
    ] }
] },
{ path: '', component: SignInComponent },
{ path: '**', component: SignInComponent }
];

В моем app.module я импортировал все, что мне нужно (я поделюсь компонентами, которые связаны с моей проблемой, потому что у меня слишком много, чтобы поделиться имиздесь)

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule, ReactiveFormsModule, FormGroup, FormBuilder } from 
'@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { FwModule } from '../fw/fw.module';
import { DashboardComponent } from './dashboard/dashboard.component';
import { SettingsComponent } from './settings/settings.component';
import { appRoutes } from './app.routing';
import { AppConfig } from './app.config';
import { BookListComponent } from './book-list/book-list.component';
import { BooksByCategoryComponent } from './books-by-category/books-by-category.component';
import { BookDetailComponent } from './book-detail/book-detail.component';
import { BookDetailUserComponent } from './bookdetail-user/bookdetail-user.component';
import { BookMaintComponent } from './book-maint/book-maint.component';
import { BookService } from './services/book.service';
import { ReviewService } from './services/review.service';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatDatepickerModule, MatDialogModule } from '@angular/material';
import { ReviewDialogComponent } from './review-dialog/review-dialog.component';

@NgModule({
  declarations: [
    AppComponent,
    DashboardComponent,
    BookListComponent,
    BooksByCategoryComponent,
    BookDetailComponent,
    BookDetailUserComponent,
    ReviewDialogComponent,
    BookMaintComponent,
    AuthenticatedUserComponent,
    ImagePanelComponent,
    BookPanelComponent,
    BookFilterPipe,
    OrderByPipe,
    StarComponent
  ],
 exports: [
// Material
MatDatepickerModule,
MatDialogModule,
MatFormFieldModule,
MatFormFieldModule
],
imports: [
   BrowserModule,
   FormsModule,
   ReactiveFormsModule,
   HttpModule,
   FwModule,
   MatDatepickerModule,
   MatNativeDateModule,
   MatFormFieldModule,
   RouterModule.forRoot(appRoutes)
],
providers: [
   UserService,
   AuthGuard,
   IsAdminGuard,
   AlertService,
   BookService,
   PagerService,
   ReviewService,
   AuthenticationService,
   CustomDateAdapter,
   AppConfig
 ],
 schemas: [CUSTOM_ELEMENTS_SCHEMA],
 bootstrap: [AppComponent],
 entryComponents: [ReviewDialogComponent],
})
export class AppModule { }

Теперь, в моем BookDetailUserComponent у меня есть кнопка, которая, по щелчку мыши, отображает модальный режим, в котором пользователь может добавить обзор с комментариями и звездочку от 1 до 5. Проблема в том, чтоЯ должен отправить bookId в ReviewDialogComponent, поэтому я пытаюсь получить родительские параметры (BookDetailUserComponent params) в дочерний компонент (ReviewDialog)

Это код из BookDetailUserComponent:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';
import { Book } from '../view-models/book';
import { Review } from '../view-models/review';
import { BookService } from '../services/book.service';
import { ReviewService } from '../services/review.service';
import { MatDialog, MatDialogConfig, MatDialogRef, MatSelectModule, 
   MatButtonModule } from "@angular/material";
import { ReviewDialogComponent } from "../review-dialog/review- 
 dialog.component";

@Component({
  selector: 'app-bookdetail-user',
  templateUrl: 'bookdetail-user.component.html'
})

export class BookDetailUserComponent implements OnInit {
 book: Book;
 review: Review;
 errorMessage: string;
 private sub: Subscription;

 reviewDialogRef: MatDialogRef<ReviewDialogComponent>;

 constructor(private route: ActivatedRoute,
   private router: Router,
   private bookService: BookService,
   private reviewService: ReviewService,
   private dialog: MatDialog) { }

ngOnInit(): void {
   this.bookService.getBook(this.route.snapshot.params['id'])
     .subscribe((book: Book) => { this.book = book });
}

addReview(review: Review) {
   const dialogConfig = new MatDialogConfig();

   dialogConfig.disableClose = true;
   dialogConfig.autoFocus = true;

   const dialogRef = this.dialog.open(ReviewDialogComponent,
     dialogConfig);

   dialogRef.afterClosed().subscribe(
    //val => console.log("Dialog output:", val)
    (review: Review) => {
      console.log("Dialog output:", review)
      }
  );
 }
}  

Шаблон для BookDetailUserComponent выглядит следующим образом:

<div class='panel-body'>
  <div class='row'>
     <div class='col-md-6'> ... </div>

     <div class='col-md-6'>
     <img class='center-block img-responsive'
         [style.width.px]='300'
         [style.margin.px]='3'
         [src]='book.imageUrl'
         [title]='book.title'>
      <button mat-button class="raised-button accent"
              (click)="addReview($event)">
        Add Review
      </button>
      </div>
   </div>
</div>

В моем ReviewDialogComponent у меня есть:

import { Component, Inject, OnInit, ViewEncapsulation, Input } from '@angular/core';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA, MatButtonModule} from "@angular/material";
import { Book } from '../view-models/book';
import { Review } from '../view-models/review';
import { BookService } from '../services/book.service';
import { ReviewService } from '../services/review.service';
import { FormBuilder, Validators, FormGroup } from "@angular/forms";
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { ActivatedRoute, Router, Params } from '@angular/router';

@Component({
  selector: 'review-dialog',
  templateUrl: './review-dialog.component.html',
  styleUrls: ['./review-dialog.component.css']
})
export class ReviewDialogComponent implements OnInit {

 errorMessage: string;
 feedbackForm: FormGroup;
 bookId: number;
 userId: number;
 date: Date;
 comments: string;
 rating: number;
 review: Review;

 private sub: any;
 private parentRouteId: number;

 public options = [
   { "id": 1, "name": "1 star" },
   { "id": 2, "name": "2 stars" },
   { "id": 3, "name": "3 stars" },
   { "id": 4, "name": "4 stars" },
   { "id": 5, "name": "5 stars" }
 ]
   public selected = this.options[0].id;

  //@Input() bId: number;

  constructor(
    private fb: FormBuilder,
    private route: ActivatedRoute,
    private router: Router,
    private dialogRef: MatDialogRef<ReviewDialogComponent>,
    private reviewService: ReviewService,
    @Inject(MAT_DIALOG_DATA) public data: any) {

      //const parentActivatedRoute = route.pathFromRoot();
     //let id = parentActivatedRoute.snapshot.parent.params['id'];  
  }

ngOnInit() {

  this.sub = this.route.parent.params.subscribe(params => {
     this.parentRouteId = +params["id"];
     console.log(this.parentRouteId);
   });

   var currentUser = JSON.parse(localStorage.getItem('currentUser'));
   this.feedbackForm = this.fb.group({
      bookId: null,
      userId: null,
      date: Date,
      comments: '',
      rating: null
   });
   this.feedbackForm.setValue({
      bookId: this.bookId,
      userId: [currentUser.userId],
      date: [new Date()],
      comments: [''],
      rating: [this.selected],
   });
  }

 save() {
    this.dialogRef.close(this.feedbackForm.value);
    if (this.feedbackForm.dirty && this.feedbackForm.valid) {
      // Copy the form values over the user object values
      let r = Object.assign({}, this.review, this.feedbackForm.value);

     this.reviewService.createReview(r)
       .subscribe(
       () => this.onCreateComplete(),
       (error: any) => this.errorMessage = <any>error
     );
   } else if (!this.feedbackForm.dirty) {
      this.onCreateComplete();
  }
 }

 onCreateComplete(): void {
   // Reset the form to clear the flags
   this.feedbackForm.reset();
   this.router.navigate(['/authenticated/dashboard']);
 }

close() {
   this.dialogRef.close();
}

}

И мой HTML-обзор ReviewDialog выглядит следующим образом:

<h1 mat-dialog-title>Add review</h1>

<form [formGroup]="feedbackForm">
  <textarea placeholder="Comments"
        formControlName="comments">
  </textarea><br>
 <br>
  <select formControlName="rating">
     <option *ngFor="let option of options" [value]="option.id">{{ option.name }}</option>
  </select><br>
  <br>
 <div>
    <button class="mat-raised-button" (click)="close()">Close</button>
    <button class="mat-raised-button" (click)="save()">Save</button>
 </div>
 </form>

Теперь ошибка, которую я продолжаю получать: " ОШИБКА TypeError: Невозможно прочитать свойство 'params' с нулевым значением в ReviewDialogComponent.ngOnInit (review-dialog.component.ts: 61)"Строка 61 - " this.sub = this.route.parent.params.subscribe (params => {"

Надеюсь, мне удалось объяснить, чего я пытаюсь достичь :) 1029 *

1 Ответ

0 голосов
/ 21 мая 2018

Итак, мне удалось заставить его работать без доступа к родительским параметрам маршрута, я добавил это в методе addReview (), до dialogRef.afterClosed () :

dialogRef.componentInstance.bookId = this.book.bookId;

и это в компоненте обзора в ngOnInit ()

 this.feedbackForm.setValue({
   bookId: this.dialogRef.componentInstance.bookId,
   ...
 });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...