Angular技术咨询:Angular5获取对象方法与单次点击获取数组异常解决
嘿,我来帮你搞定这两个Angular的问题!
在Angular 5里获取对象的场景有很多,我给你列几种最常用的方式:
从HTTP请求获取单个对象
用HttpClient发起GET请求,指定返回类型就能直接拿到对应对象:// 服务代码 import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Person } from './person.model'; import { Observable } from 'rxjs'; @Injectable() export class PersonService { constructor(private http: HttpClient) {} // 获取单个Person对象 getSinglePerson(id: number): Observable<Person> { const url = `assets/Json/person${id}.json`; return this.http.get<Person>(url); } }然后在组件里订阅请求结果:
// 组件代码 import { Component, OnInit } from '@angular/core'; import { PersonService } from './person.service'; import { Person } from './person.model'; @Component({ selector: 'app-person', templateUrl: './person.component.html' }) export class PersonComponent implements OnInit { person: Person; constructor(private personService: PersonService) {} ngOnInit() { this.personService.getSinglePerson(1).subscribe(data => { this.person = data; console.log('拿到的对象:', this.person); }); } }从共享服务中获取对象
如果服务里已经缓存了对象实例,直接访问服务的属性或方法即可(注意异步场景的坑,比如你第二个问题里的情况):// 服务代码 export class ConexionPersonService { _person: Person; // 假设已经通过请求初始化了_person getPerson(): Person { return this._person; } } // 组件里调用 this.person = this.conexionPersonService.getPerson();从路由参数获取对象(先拿ID再请求)
如果路由里带了对象的ID参数,先获取ID再发起请求:// 组件代码 import { ActivatedRoute } from '@angular/router'; constructor(private route: ActivatedRoute, private personService: PersonService) {} ngOnInit() { this.route.paramMap.subscribe(params => { const personId = +params.get('id'); this.personService.getSinglePerson(personId).subscribe(data => { this.person = data; }); }); }从本地存储获取对象
如果对象存在localStorage或sessionStorage里,取出后解析成对象:const storedPerson = localStorage.getItem('currentPerson'); if (storedPerson) { this.person = JSON.parse(storedPerson) as Person; }
先给你分析问题根源:你的getPeople()方法里,http.get是异步操作——subscribe里的回调函数要等HTTP请求完成后才会执行,但你在subscribe外面直接打印this._people,这时候请求还没结束,this._people还是undefined。第一次点击按钮时,请求发出去了但数据还没回来,组件拿不到值;第二次点击时,之前的请求已经完成,this._people被赋值了,所以能拿到数据。
下面给你几种靠谱的解决方案:
方案1:让服务返回Observable,组件里订阅处理
修改服务代码,直接返回HTTP请求的Observable,让组件在订阅时处理数据:
@Injectable() export class ConexionPersonService { constructor(private http: HttpClient) { } public getPeople(): Observable<Person[]> { const url = 'assets/Json/listPerson.json'; return this.http.get<Person[]>(url); } }
组件里点击按钮时订阅:
// 组件代码 import { Component } from '@angular/core'; import { ConexionPersonService } from './conexion-person.service'; import { Person } from './person.model'; @Component({ selector: 'app-people', templateUrl: './people.component.html' }) export class PeopleComponent { people: Person[]; constructor(private conexionPersonService: ConexionPersonService) {} onGetPeople() { this.conexionPersonService.getPeople().subscribe(data => { this.people = data; console.log('拿到的数组:', this.people); // 这里可以写拿到数据后的逻辑,比如渲染页面 }); } }
这样每次点击按钮,请求完成后直接拿到数据,一次点击就生效。
方案2:用Subject在服务里通知组件(适合缓存数据的场景)
如果需要在服务里缓存数组,同时让组件实时收到更新,可以用RxJS的Subject:
import { Subject } from 'rxjs'; import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Person } from './person.model'; @Injectable() export class ConexionPersonService { private peopleSubject = new Subject<Person[]>(); // 对外暴露Observable,避免组件直接修改Subject people$ = this.peopleSubject.asObservable(); private _people: Person[]; constructor(private http: HttpClient) { } public getPeople(): void { const url = 'assets/Json/listPerson.json'; this.http.get<Person[]>(url).subscribe(data => { this._people = data; this.peopleSubject.next(data); // 把数据推给订阅的组件 console.log('获取到数组:', this._people); }); } }
组件里提前订阅people$:
// 组件代码 import { Component, OnInit } from '@angular/core'; import { ConexionPersonService } from './conexion-person.service'; import { Person } from './person.model'; @Component({ selector: 'app-people', templateUrl: './people.component.html' }) export class PeopleComponent implements OnInit { people: Person[]; constructor(private conexionPersonService: ConexionPersonService) {} ngOnInit() { // 订阅数据更新 this.conexionPersonService.people$.subscribe(data => { this.people = data; }); } onGetPeople() { this.conexionPersonService.getPeople(); } }
方案3:使用Async管道(推荐,减少手动订阅)
这个方案不用手动写订阅,Angular的Async管道会自动处理订阅和取消订阅,还能避免内存泄漏:
// 组件代码 import { Component } from '@angular/core'; import { ConexionPersonService } from './conexion-person.service'; import { Observable } from 'rxjs'; import { Person } from './person.model'; @Component({ selector: 'app-people', templateUrl: './people.component.html' }) export class PeopleComponent { people$: Observable<Person[]>; constructor(private conexionPersonService: ConexionPersonService) {} onGetPeople() { this.people$ = this.conexionPersonService.getPeople(); } }
模板里用Async管道渲染:
<button (click)="onGetPeople()">获取人员列表</button> <ul *ngIf="people$ | async as people"> <li *ngFor="let person of people">{{person.name}}</li> </ul>
这样点击一次按钮,数据回来后页面会自动更新,非常省心。
内容的提问来源于stack exchange,提问作者EduBw

