【问题标题】:reloading page makes variable undefined in Angular重新加载页面使变量在 Angular 中未定义
【发布时间】:2020-04-21 09:02:32
【问题描述】:

我有一个甲板构建器,一个显示甲板列表的甲板列表组件,当我单击甲板时,使用甲板的 id 和路由加载正确的甲板详细信息组件。这是我使用路线的甲板细节部分。

 ngOnInit(){
 this.decks = this.deckService.getDecks(); // this just returns the array of decks
 this.id = this.route.snapshot.params["id"];
    this.paramsSubscription = this.route.params.subscribe((params: Params) => {
      this.id = params["id"];
      console.log(this.id);
      this.deck = this.decks.find((deck) => deck.id === this.id);
      console.log("deck-detail deck", this.deck);
}

这是app-routing.module

const appRoutes: Routes = [
  { path: '', component: CardListComponent },
  { path: 'decks', component: DeckListComponent, children: [
    { path: ':id/:deckName', component: DeckDetailsComponent }
  ] },
  { path: 'createDeck', component: CreateDeckComponent },
];
@NgModule({
  imports: [RouterModule.forRoot(appRoutes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

所以当我点击一个卡片组时,url 变成了这样:localhost:4200/decks/id/deckName。 如果在 url 是这样的时候重新加载页面,deck-detail 组件不会与页面一起重新加载,我得到这个错误

TypeError: Cannot read property 'deckName' of undefined
    at DeckDetailsComponent_Template

我做错了什么?存在组件生命周期问题?重新加载页面时如何避免卡组未定义?

【问题讨论】:

  • 重新加载期间console.log(this.id); 是什么
  • 打印出正确的id
  • 你需要使用this.routes.params.subscribe()来读取id和deckName的值
  • 我已经在deck-details组件中使用它
  • @Syertim 你能显示你的DeckService吗,你的牌组是异步的吗?

标签: javascript angular routing


【解决方案1】:

这是整个甲板细节组件

import { Card } from "./../../card/card.model";
import { Deck } from "./../../deck/deck.model";
import { Component, OnInit, Input } from "@angular/core";
import { DeckService } from "src/app/deck/deck.service";
import { ActivatedRoute, Params, Router } from "@angular/router";
import { Subscription } from "rxjs";
import { DataStorageService } from "src/app/shared/data-storage.service";
import { CardService } from "src/app/card/card.service";
import { FormControl, FormGroup } from "@angular/forms";

@Component({
  selector: "app-deck-details",
  templateUrl: "./deck-details.component.html",
  styleUrls: ["./deck-details.component.scss"],
})
export class DeckDetailsComponent implements OnInit {
  //@Input() deck: Deck;
  paramsSubscription: Subscription;
  id: number;
  decks: Deck[];
  deck: Deck;
  cards: Card[];
  selectedClassCards: Card[];
  classes = [
    "Priest",
    "Mage",
    "Shaman",
    "Rogue",
    "Warrior",
    "Warlock",
    "Druid",
    "Paladin",
  ];
  addCardForm: FormGroup;

  constructor(
    private deckService: DeckService,
    private cardService: CardService,
    private route: ActivatedRoute,
    private dataStorageService: DataStorageService
  ) {}

  ngOnInit() {
    this.addCardForm = new FormGroup({
      deckCards: new FormControl(),
    });
    this.cards = this.cardService.getCards();
    this.decks = this.deckService.getDecks();
    this.id = this.route.snapshot.params["id"];
    this.paramsSubscription = this.route.params.subscribe((params: Params) => {
      this.id = params["id"];

      this.deck = this.decks.find((deck) => deck.id === this.id);
      console.log("deck-detail deck", this.deck);
      this.selectedClassCards = this.cards.filter(
        (card) => card.hero === this.deck.deckClass || card.hero === "Neutral"
      );
    });
  }

  onDeleteCard(i) {
    this.deckService.deleteCard(this.deck, this.deck.deckCards[i]);
    //this.deckService.cardsChanged.next(this.deck.deckCards.slice());
    console.log(this.deck);
  }
  onAddCard() {
    this.deckService.addCard(this.deck, this.addCardForm.value.deckCards);
    console.log(this.deck);
  }

  onCardsEdit() {
    this.dataStorageService.storeCards(
      this.decks.indexOf(this.deck),
      this.deck.deckCards
    );
  }

  ngOnDestroy() {
    this.paramsSubscription.unsubscribe();
  }
}

这就是 DeckService

import { DataStorageService } from './../shared/data-storage.service';
import { Deck } from './deck.model';
import { Card } from '../card/card.model';
import {EventEmitter, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs';

@Injectable()
export class DeckService {
  deckSelected = new EventEmitter<Deck>();
  decksChanged = new Subject<Deck[]>();
  cardsChanged = new Subject<Card[]>();

  decks: Deck[] = [];
  remainingDecks: Deck[];


  constructor(/* private http: HttpClient, */ /* private dataStorageService: DataStorageService */) {}

  setDecks(decks: Deck[]) {
    this.decks = decks;
    this.decksChanged.next(this.decks.slice());
  }
  getDecks() {
    if (this.decks) {
      return this.decks.slice();
    }

}

  addCard(deck: Deck, card: Card){
    deck.deckCards.push(card);
}
  deleteCard(deck: Deck,  card: Card){
    deck.deckCards.splice( deck.deckCards.indexOf(card), 1);
  }

addNewDeck(deck: Deck){
  this.decks.push(deck);
  this.decksChanged.next(this.decks.slice());

};

deleteDeck(id: number) {
this.remainingDecks = this.decks.filter(
  deck => deck.id !== id
)
this.decks = this.remainingDecks;
this.decksChanged.next(this.decks.slice());
}

}


这是我用火力基地和 httpClient 存储和获取套牌的地方

import { DeckService } from "./../deck/deck.service";
import { CardService } from "./../card/card.service";
import { Deck } from "./../deck/deck.model";
import { Card } from "./../card/card.model";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { map, tap } from "rxjs/operators";

@Injectable({ providedIn: "root" })
export class DataStorageService {
  constructor(private http: HttpClient, private deckService: DeckService) {}

  storeDecks() {
    const decks = this.deckService.getDecks();
    this.http
      .put("https://ang-cards.firebaseio.com/decks.json", decks)
      .subscribe((response) => {
        console.log(response);
        console.log("stored");
      });
  }
  fetchDecks() {
    return this.http
      .get<Deck[]>("https://ang-cards.firebaseio.com/decks.json")
      .subscribe((decks) => {
        decks
          ? this.deckService.setDecks(decks)
          : this.deckService.setDecks([]);
        console.log("fetching", decks);
      });
  }
  storeCards(i: number, cards: Card[]){
    this.http
    .put("https://ang-cards.firebaseio.com/decks/" + i + "/deckCards.json", cards)
    .subscribe((response) => {
      console.log(response);
      console.log("cards stored");
    });
  }
}

【讨论】:

  • 使用 behaviorsubject 代替 this `decksChanged = new Subject();`
  • 你能更好地解释一下你的意思吗?
【解决方案2】:

有关信息,这是甲板细节组件 html 模板

<div class="container">
  <div class="row">
    <div class="deck-details  " style="border:solid black">
      <!-- <img
        [src]="'../../assets/img/' + deck.deckClass + '.png'"
        alt="{{ deck.deckName }}"
        class="img-responsive"
        style="height: 200px;"
      /> -->

      <h1 contenteditable="true">{{ deck.deckName }} : {{ deck.deckClass }}</h1>
      <div *ngFor="let card of deck.deckCards; let i = index" >
        <span
      [ngClass]="{
        common: card.rarity == 'common',
        rare: card.rarity == 'rare',
        epic: card.rarity == 'epic',
        legendary: card.rarity == 'legendary'
      }"
    >
      {{ card.name }}
    </span>
    <h4 class="inlineh4">: {{ card.manaCost }} mana</h4>
    <button class="btn btn-danger" (click) = "onDeleteCard(i)" >delete</button>
       <!--  <img [src]="card.imagePath" alt="" style="height: 20px;" /> -->
      </div>
      <hr>
      <label for="deckCards">Add a Card</label>
      <form [formGroup]="addCardForm">
        <select formControlName="deckCards" id="deckCards" name="deckCards">
          <option *ngFor="let card of selectedClassCards" [ngValue]="card">
            {{ card.name }}
          </option>
        </select>
        <button (click)="onAddCard()" type="button" class="btn btn-primary">
          Add Card
        </button>
      </form>
      <hr>
      <button class="btn btn-primary"(click) = "onCardsEdit()" >Save changes</button>
    </div>
  </div>
</div>

【讨论】:

    猜你喜欢
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 2013-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多