简体   繁体   English

角度:访问在“ OnInit”函数中声明的this.id

[英]Angular: Access this.id declared in an “OnInit” function

Update 1 更新1

After I read Alexanders suggestions, I updated the code and got no error back. 在阅读了Alexanders的建议之后,我更新了代码,没有错误返回。 But Angular doesn't do a request to the server anymore, which make me curious. 但是Angular不再向服务器发出请求,这使我感到好奇。 And also the pageTitle does not update. 而且pageTitle也不会更新。

appointmentDetail.component.html appointmentDetail.component.html

{{appointmentDetail.time}}

appointmentDetail.component.ts appointmentDetail.component.ts

import { Component, OnInit, OnDestroy, Injectable } from '@angular/core';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { APIService } from './../../../api.service';
import { Observable } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';

@Component({
  selector: 'app-appointmentdetail',
  templateUrl: './appointmentDetail.component.html',
  styleUrls: ['./appointmentDetail.component.scss']
})
export class AppointmentDetailComponent implements OnInit {
  id: any;
  appointmentDetail$: Observable<Object>; // I'd really create an interface for appointment or whatever instead of  object or any
  pageTitle = 'Some Default Title Maybe';

  constructor(
    private route: ActivatedRoute,
    private title: Title,
    private apiService: APIService
  ) {}

  ngOnInit() {
    this.appointmentDetail$ = this.route.paramMap.pipe(
      tap((params: ParamMap) => {
        this.id = params.get('id');
        // Or this.id = +params.get('id'); to coerce to number maybe
        this.pageTitle = 'Termin' + this.id;
        this.title.setTitle(this.pageTitle);
      }),
      switchMap(() => this.apiService.getAppointmentDetailsById(this.id))
    );
  }
  public getData() {
    this.apiService
      .getAppointmentDetailsById(this.id)
      .subscribe((data: Observable<Object>) => {
        this.appointmentDetail$ = data;
        console.log(data);
      });
  }
}

api.service.ts api.service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class APIService {
  API_URL = 'http://localhost:5000';
  constructor(private httpClient: HttpClient) {}
  getAppointments() {
    return this.httpClient.get(`${this.API_URL}/appointments/`);
  }
  getAppointmentDetailsById(id) {
    return this.httpClient.get(`${this.API_URL}/appointments/${id}`);
  }
  getAppointmentsByUser(email) {
    return this.httpClient.get(`${this.API_URL}/user/${email}/appointments`);
  }
  getCertificatesByUser(email) {
    return this.httpClient.get(`${this.API_URL}/user/${email}/certificates`);
  }
}

As you can see, I want to grab that parameter id from the router parameters and want to pass it into my API call, which will do a Angular HTTP request. 如您所见,我想从路由器参数中获取该参数id ,并将其传递到我的API调用中,该API调用将执行Angular HTTP请求。 Hope I'm right, haha. 希望我是对的,哈哈。


Original Question 原始问题

Currently, I ran into a nasty problem. 目前,我遇到了一个令人讨厌的问题。 The thing is, I want to read the params, which are given to me by ActivatedRouter and the Angular OnInit function. 问题是,我想阅读由ActivatedRouter和Angular OnInit函数提供给我的参数。 I subscribe them params and log them in the console. 我订阅了它们的参数并将其记录在控制台中。 Until here, everything is working fine. 到这里为止,一切工作正常。 But I want to access " this.id " outside from my OnInit function, so I can use it on pageTitle for example. 但是我想从OnInit函数外部访问“ this.id ”,因此我可以在例如pageTitle上使用它。

But, this.id is undefined. 但是,this.id是未定义的。 So the page title is Termineundefined. 因此页面标题是Termineundefined。

Source code: 源代码:

import { Component, OnInit, OnDestroy, Injectable } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { APIService } from './../../api.service';

@Component({
  selector: 'app-appointment-details',
  templateUrl: './appointment-details.component.html',
  styleUrls: ['./appointment-details.component.scss']
})
@Injectable()
export class AppointmentDetailsComponent implements OnInit, OnDestroy {
  private routeSub: any;
  id: any;
  private appointmentDetail: Array<object> = [];
  constructor(
    private route: ActivatedRoute,
    private title: Title,
    private apiService: APIService
  ) {}

  pageTitle = 'Termin' + this.id;

  ngOnInit() {
    this.title.setTitle(this.pageTitle);
    this.getData();

    this.routeSub = this.route.params.subscribe(params => {
      console.log(params);
      this.id = params['id'];
    });
  }

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

  public getData() {
    this.apiService
      .getAppointmentDetailsById(this.id)
      .subscribe((data: Array<object>) => {
        this.appointmentDetail = data;
        console.log(data);
      });
  }
}

The issue here really comes down to async availability of route params and observable streams. 这里的问题实际上归结为路由参数和可观察流的异步可用性。 You simply cannot use the value until it has resolved for all practical purposes. 您不能使用该值,直到将其解析为所有实际用途为止。 You can use RxJS operators such as switchMap and tap in line with the official Routing & Navigation documentation to ensure route param id is available prior to use. 您可以使用RxJS运营商如switchMaptap符合官方的路线选择和导航文件,以确保航线PARAM id ,请在使用前。 tap can be used to introduce side effects such as setting class id property from route params and/or setting title. tap可以用于引入副作用,例如从路由参数设置类别id属性和/或设置标题。 You could even create a class property of an Observable<YourObject[]> and utilize Angular Async Pipe to avoid subscribing and unsubscribing to display the data. 您甚至可以创建Observable<YourObject[]>的类属性,并利用Angular Async Pipe避免订阅和取消订阅来显示数据。

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { APIService, MyFancyInterface } from './../../api.service';
import { Observable } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';

@Component({
  selector: 'app-appointment-details',
  templateUrl: './appointment-details.component.html',
  styleUrls: ['./appointment-details.component.scss']
})
export class AppointmentDetailsComponent implements OnInit {
  id: any;
  appointmentDetail$: Observable<MyFancyInterface>;
  appointmentDetail: MyFancyInterface;
  pageTitle = 'Some Default Title Maybe';

  constructor(
    private route: ActivatedRoute,
    private title: Title,
    private apiService: APIService
  ) {}

  ngOnInit() {
    this.appointmentDetail$ = this.route.paramMap.pipe(
      tap((params: ParamMap) => {
        this.id = params.get('id')
        // Or this.id = +params.get('id'); to coerce to type number maybe
        this.pageTitle = 'Termin' + this.id;
        this.title.setTitle(this.pageTitle);
      }),
      switchMap(() => this.apiService.getAppointmentDetailsById(this.id))
    );

    /* Or
    this.route.paramMap.pipe(
      tap((params: ParamMap) => {
        this.id = params.get('id')
        // Or this.id = +params.get('id'); to coerce to type number maybe
        this.pageTitle = 'Termin' + this.id;
        this.title.setTitle(this.pageTitle);
      }),
      switchMap(() => this.apiService.getAppointmentDetailsById(this.id))
    ).subscribe((data: MyFancyInterface) => {
      this.appointmentDetail = data;
    });
    */
  }

}

Template: 模板:

<div>{{(appointmentDetail | async)?.id}}</div>

I'd recommend to create an interface to represent your data model and type the return of your api service method: 我建议创建一个接口来表示您的数据模型,并键入api服务方法的返回值:

import { Observable } from 'rxjs';

// maybe put this into another file
export interface MyFancyInterface {
  id: number;
  someProperty: string;
  ...
}

export class APIService {
  ...
  getAppointmentDetailsById(id): Observable<MyFancyInterface> {
    return this.httpClient.get<MyFancyInterface>(`${this.API_URL}/appointments/${id}`);
  }
  ...
}

If you really must, you can save the observable as you do now for the route params and subscribe as needed in the various parts of the class, but this demonstrated way you almost absolutely know that route param id will be available for use and can explicitly set the things you need to set. 如果确实需要,您可以像现在所做的那样保存路由参数的可观察对象,并根据需要在课程的各个部分进行订阅,但是通过这种演示方式,您几乎可以完全知道路由参数id可以使用,并且可以显式地使用设置您需要设置的东西。

I'd also remove @Injectable() as there is no reason to have it here with a @Component() decorator. 我还将删除@Injectable()因为没有理由在这里使用@Component()装饰器。

Note* the async pipe operator in this example ensures the Http call is executed. 注意*此示例中的异步管道运算符确保执行Http调用。 Otherwise a subscribe() is needed (search SO for Angular http not executing to see similar issues) 否则需要一个subscribe()(在SO中搜索Angular http无法执行以查看类似问题)

Hopefully that helps! 希望有帮助!

Instead of 代替

id: any;

You could try using a getter, like so 您可以像这样尝试使用吸气剂

public get id(): any {
  this.route.params.subscribe(params => {
    return params['id'];
   }
}

In your template, just 在您的模板中,

{{ id }}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM