【问题标题】:Trying to pass object from api to child component using Input Decorator尝试使用输入装饰器将对象从 api 传递给子组件
【发布时间】:2020-11-17 04:20:54
【问题描述】:

我有一个父组件,它使用服务从 api 接收数据。我需要将此数据传递给子组件,因为我不想再次调用 api(严格规则)。我可以访问我的父组件中的数据,但我没有在我的子组件中获取它。我尝试了很多不同的方法。

import { Component, OnInit, ViewChild } from '@angular/core';
import {ActivatedRoute} from "@angular/router";
import {SwapiService} from "../../models/swapi.service";
import {Starship} from "../../models/starship";
// import {MatTableDataSource} from '@angular/material/table';
// import {MatPaginator} from '@angular/material/paginator';


@Component({
  selector: 'app-starships',
  templateUrl: './starships.component.html',
  styleUrls: ['./starships.component.css']
})
export class StarshipsComponent implements OnInit {
  public starship: Starship[]
  url: string;

  constructor(private swapi: SwapiService, private route: ActivatedRoute) {


  }


  ngOnInit(): void {
  this.loadStarshipList();

  }
  loadStarshipList(): void {
    this.swapi.getStarshipList().subscribe(
      res => {
        this.starship = res;
        console.log(res);

      }
    )
  }

}

父模板

span *ngIf="starship">
<p *ngFor="let res of starship?.results" >{{res?.name}}
  <app-starship *ngFor="let res of starship.results" [data]="res?.results"></app-starship>
<!--  <span [res1]="res1"></span>-->
  <button routerLink="/starships/{{res?.url}}">Starship Details</button>
</p>
</span>

子组件

import { Component, Input, OnInit } from '@angular/core';
// import {Starships} from "../../models/starship";
import {SwapiService} from "../../models/swapi.service";
import {ActivatedRoute} from "@angular/router";
import {StarshipsComponent} from "../starships/starships.component";

@Component({
  selector: 'app-starship',
  templateUrl: './starship.component.html',
  styleUrls: ['./starship.component.css']
})
export class StarshipComponent implements OnInit {
  // public starship: Starship[]
  private url: string;
  @Input() data;

  constructor(private swapi: SwapiService,
              private route: ActivatedRoute,
              private activatedRoute: ActivatedRoute,

  ) {
  }

  ngOnInit(): void {
    this.url = this.route.snapshot.paramMap.get('url');
    console.log(this.url);


  }

}

子模板

<span *ngIf="data"></span>
<div *ngFor="let res of data">
  <h1>{{data?.name}}</h1>
  <p>{{data?.url}}</p>
</div>
hi

没有回应。

我正在尝试使用 BehaviorSubject,以便在多个组件之间共享数据。我的问题是,我不知道如何将数据从我的函数传输到一个变量,以便我可以在其他组件中使用它。

这是我的服务文件:

import { Injectable } from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {BehaviorSubject, Observable} from "rxjs";
import {map, skipWhile, tap} from 'rxjs/operators';
import {Starship} from "./starship";


@Injectable({
  providedIn: 'root'
})
export class SwapiService {
  private apiData = new BehaviorSubject<Starship[]>(null)
  public currentData = this.apiData.asObservable()
  baseURL = 'https://swapi.dev/api/';

  constructor(private http: HttpClient) { }

  getStarshipList(page?: number): Observable<Starship[]> {
    return this.http.get<Starship[]>(`${this.baseURL}starships?format=json${this.getByPage(page)}`)
      .pipe(
        map(resp => resp['results']),)
    ;
  }

  getByPage(page: number): string {
    if (page) { return '&page=' + page; } else { return ''; }
  }


  setData(data) {
    this.apiData.next(data)
    }


}

如何将 getStarshipList 接收到的数据传输到变量中,然后我可以使用 setData 函数传递它。我知道这似乎是一个愚蠢的问题,但我尝试了许多不同的方法,但都无法正确解决。

@Abhinav 阿加瓦尔

我想出了如何在两个组件中使用它而不在服务中声明变量,但我仍然想知道

【问题讨论】:

  • 你能在这里分享响应的完整对象吗?
  • {count: 36, next: "http://swapi.dev/api/starships/?page=2", previous: null, results: Array(10)} count: 36 next: "http://swapi.dev/api/starships/?page=2" previous: null results: Array(10) 0: MGLT: "60"
  • cargo_capacity: "3000000" consumables: "1 year" cost_in_credits: "3500000" created: "2014-12-10T14:20:33.369000Z" crew: "30-165" edited: "2014-12-20T21:23:49.867000Z" films: (3) ["http://swapi.dev/api/films/1/", "http://swapi.dev/api/films/3/", "http://swapi.dev/api/films/6/"] hyperdrive_rating: "2.0" length: "150" manufacturer: "Corellian Engineering Corporation" max_atmosphering_speed: "950" model: "CR90 corvette" name: "CR90 corvette" passengers: "600" pilots: [] starship_class: "corvette" url: "http://swapi.dev/api/starships/2/" __proto__: Object@Sivakumar Tadisetti @uiTeam324
  • 请不要向 cmets 发布此类内容,请在您的问题下方使用 edit 链接。

标签: angular input angular-decorator


【解决方案1】:

注意导入所需的库,例如:主题

子组件

@Input() data: BehaviorSubject<any>;
ngUnsubscribe: any = new Subject();
ngOnInit(){
this.listenParentDataChanges();
}
listenParentDataChanges() {
    if (this.data) {
      this.data.asObservable().takeUntil(this.ngUnsubscribe)
        .subscribe(responseData => {
           console.log("-data--",data);
        });
    } 
  }

父组件

shareData: BehaviorSubject<any> = new BehaviorSubject({});

下面的代码写你从后端接收数据的位置。

this.shareData.next({ data: responseData});

html

<app-starship *ngFor="let res of starship.results" [data]="shareData"></app-starship>

【讨论】:

    【解决方案2】:

    你也可以使用BehaviorSubject

    service.ts

    private sList = new BehaviorSubject<any>(null);
    
    getStarshipList() {
    return this.http.get(`url`).pipe(
      tap((data: any) => this.sList.next(data);
    );
    }
    
    getSlist() {
    return this.sList.asObservable().pipe(skipWhile(val => val === null));
    }
    

    parent.component.ts

    ngOnInit(){
       this.loadStarshipList();
    
      }
      loadStarshipList(){
        this.swapi.getStarshipList().subscribe(
          res => {
            this.starship = res;
            console.log(res);
    
          }
        )
      }
    

    child.component.ts

    data:any;
    
    ngOnInit()
    this.swapi.getSList().subscribe(
          res => {
            this.data = res;
            console.log(res);
    
          }
        )
        }
    

    【讨论】:

      【解决方案3】:

      您不需要在父模板上使用多个 ngFor。将res 直接传递给包含result 数组的子元素。

      <p *ngFor="let res of starship?.results" >{{res?.name}}
       <app-starship [data]="res"></app-starship>
      

      子组件:

        ngOnInit(): void {
         console.log(this.data); //check you have data or not here
       }
      

      【讨论】:

      • 我在创建演示时遇到问题。如果我如上所述执行 ngif,则会收到错误无法读取未定义的属性“长度”。同上,如果我 console.log(this.data),它是未定义的。
      • 当我在父组件中 console.log(this.starship) 时,这是我的结果:{count: 36, next: "http://swapi.dev/api/starships/?page=2", previous: null, results: Array(10)} count: 36 next: "http://swapi.dev/api/starships/?page=2" previous: null results: Array(10) 0: MGLT: "60"
      • cargo_capacity: "3000000" consumables: "1 year" cost_in_credits: "3500000" created: "2014-12-10T14:20:33.369000Z" crew: "30-165" edited: "2014-12-20T21:23:49.867000Z" films: (3) ["http://swapi.dev/api/films/1/", "http://swapi.dev/api/films/3/", "http://swapi.dev/api/films/6/"] hyperdrive_rating: "2.0" length: "150" manufacturer: "Corellian Engineering Corporation" max_atmosphering_speed: "950" model: "CR90 corvette" name: "CR90 corvette" passengers: "600" pilots: [] starship_class: "corvette" url: "http://swapi.dev/api/starships/2/" __proto__: Object
      • 另外,请注意,在父组件的模板中,当我使用*ngFor="let res of starship?.results"&gt;{{res?.name}} {{res.url}} {{res.model}}时,结果会产生错误(它变成红色并且错误说是Unresolved variable results),但它仍然给出我的名称,网址和型号的数据。它生成它,但它看起来不正确
      • 根据您的响应结构修改了答案。
      【解决方案4】:

      建议:- 首先了解生命周期钩子是如何工作的。以及为什么 Angular 引入了 ngOnChanges。 研究生命周期挂钩和变更检测。

      你的问题:- 您正在将变量从父级传递给子级。在父级的初始阶段没有数据并且未定义。 您已经将其传递给子组件,因此您没有数据。 Api 在两个视图都已创建后提供数据。并且角度组件不知道数据已更改。

      解决方案:-

      选项一:父组件收到数据后,你应该创建子组件。

      选项 2:订阅父组件以进行更改检测

      选项 3:对父组件和子组件进行更改检测。

      【讨论】:

        【解决方案5】:

        在您的子组件中......在 ngOnInIt 方法使用上述代码并从 angular/core 导入和实现 ngOnChanges 之后,我希望它会起作用。

        导入:从 '@angular/core' 导入 { OnChanges };

        实现: 导出类 StarshipComponent 实现 OnInit、OnChanges { }

        ngOnChanges(changes: SimpleChanges): void {
           if (changes.data.currentValue) {
             this.data = changes.data.currentValue;
           }
        }
        
          
        

        【讨论】:

        • 在你的子组件中......在 ngOninIt 方法使用上面的代码并从 angular/core 导入和实现 ngOnchange 之后,我希望它能工作......谢谢
        • 从 '@angular/core' 导入 { OnChanges };
        • 导出类 StarshipComponent 实现 OnInit, OnChanges { }
        猜你喜欢
        • 2021-02-11
        • 2015-12-13
        • 2021-10-13
        • 1970-01-01
        • 1970-01-01
        • 2019-01-25
        • 2021-04-09
        • 2021-11-21
        • 2019-07-24
        相关资源
        最近更新 更多