共享服务变量未定义?

时间:2018-01-17 14:04:18

标签: angular

我的服务有以下方法:

public GetCaseData(){

const url =  environment.api_url;

const headers = new Headers();
headers.append('Content-Type', 'application/json');
return this._http.get(url, { headers: headers })
    .map(response => {
        return response.json();
    });
}

在我的app.component.ts中,我这样称呼它:

  constructor(private _caseService : CaseService) {}

  ngOnInit(): void {

    this._caseService.GetCaseData().subscribe(data => {
      this._caseService.caseData = data;

    });

  }

我想将this._caseService.caseData分享给我的其他组件HomeContact,但在这些组件的OnInit中,this._caseService.caseData未定义。 这里是家庭,例如,

 constructor(private _caseService: CaseService) { }

  ngOnInit() {
    console.log(this._caseService.caseData); //is undefined here because it
                                            // is called before the data comes back
}

我知道原因(因为组件在数据恢复之前已初始化),但我不确定如何修复它?

我把一个吸气剂放在家里,我看到了数据。在返回数据后,生命周期中是否会调用getter:

  ngOnInit() {
    this.data = this._caseService.caseData;
    console.log('this.data ', this.data) //undefined
  }

  get caseData()
  {
    return this._caseService.caseData; //data rendered on html page
  }

当我执行以下操作时,它表示希望:代替data.它还会抱怨,关闭ngOnInit } }}

ngOnInit(){     this.concatCaseData $ = this._caseService.caseData $ .map(data => {      return {data.OfficialCaseName}    }

}

2 个答案:

答案 0 :(得分:2)

要添加Elseo答案,Getter会解决您的问题,因为它一直被调用。

另一种替代方案,我认为是更好的解决方案,是使用BehaviorSubject。你可以给它一个初始状态并订阅它。

例如,您的160301002a0200002603015a5f5e17f78944857a7c58166f62f874063ace76daf1225b4dec0b3b586eb953000035001603010c800b000c7c000c790005b8308205b43082039c020101300d06092a864886f70d0101050500308198310b3009060355040613025541310d300b060355040813044b696576310d300b060355040713044b69657631143012060355040a130b43727974656b20476d624831153013060355040b130c546563686f7073205465616d311730150603550403130e7777772e63727974656b2e636f6d3125302306092a864886f70d0109011616616c6578616e6465726b6f4063727974656b2e636f6d301e170d3135313031353139343331395a170d3335313031303139343331395a3081a6310b3009060355040613025541310d300b060355040813044b696576310d300b060355040713044b696576311e301c060355040a141543727974656b20476d6248207c205761726661636531153013060355040b130c546563686f7073205465616d311b301906035504031312776172666163652e63727974656b2e636f6d3125302306092a864886f70d0109011616616c6578616e6465726b6f4063727974656b2e636f6d30820222300d06092a864886f70d01010105000382020f003082020a0282020100a7cd8444bdbd68abca318cc50a94fda5cee4954d109d324d7607d68ef3d1d9b78f0714582a9fca42c043f6348450a96e55831ade93cf6d00faf234b0a84e9390a83b73716d9c498f4882ed039ba04e969bed87bd0e5539f5e5f4a5a8c7a86b9f868361d38727a70d9c1e8a42a6851c8744eac0e83f081eeb18a11a4738e18ccd1ae1094971c0e8e84efa4e116e8a7ae22faa88eaf4b5484c5734fc2b4ce097f5782ef371ce3f33d83b503e9d8a37abe8e76641b923bdaaacd65f399d36a9edeef420de58b29088972d048f1fb9e57807ffb842d49ec93aa61539dfd3c3bd676790207bb2a2ec8078c3f12bb5d38d755ad691135b00304c73a8983c6133f2602f9497c3e0a6fe5d34d379550728184b878714c2d9e775a27b6025003e1e9644d38a0f63cfa0acb082d38383c95a93668e37bb8dadafc0a831e2e390d2d7b1c40b6daf552a7cef87e586123333584b1862eb1a762755e1ec6ff9bea52eb12881462ac1a497b0f8f9ed96220b005e5696f28461c20f9dab148cee03737e7842ceeccb8a626f504f286ae6de90889d91404a87838528f8defc2fcb00b78fcf8a1157d8164b3d4d5de716d5498bafa41c53f6500fd2dfe057519fa9e4bdede2b0c9d2a95e4706866b020bbdf79505fad53a199ea3facfbcfcbbe9459688bf83123c8f902e4002fa828fe3e59156c99a81041d62e0b362af381624d50272ce7c3c056d0203010001300d06092a864886f70d010105050003820201001a337ddb2ab892bf01008234fe8733cef1741d17172aa1a3f99346809144901d68d9b53e67d5a56c247d614fc8408e2cde98ee8564ccb821534d8796d083a2e4556def2e35cbf7e2b34edcf1b0154ce715c4f47cfa8d7e1b92d359816b4819ba08d3cb124afe8ab742c31927e5e160c54a50824abf26fe7ae65532381346bd234cf1ee5e7cd1a746cb4770dac66071adfc7c3951f2d2627b612bf7608632c5b89848d64b54513b96942234d4d9266ce28b729da9b2d7df9fd791f6fe5f0da2398a9a5fa1efe9856633f62e4beb3e76a94b2c6ece93426f33078bd97c4a582b42948fe921e87af4e7638de8bfb3329f9680595ffc59b35b9777fa2c8a045850e4af2d90e44a72c426d4d98e964d02bb0554cd341a9f33fd402b5c6021ca952ef9c7b14acf5d683989066c2400455fda8064bd67acdc516f6da29de79fef8cb2fc0aefd03b47ab7380a77abca0e097661e02ffa7c1b069118f94c7a0873edd2e0faf653dee67ace0a9e5ad4837545b677c8a2a74c445771d6da38c4b6a04274808635f9af6dcfaacc5b89c77e85cef4caaa0010da7fc010419209f2f465acd46de3e177d473d00d8524d627db6baf6359a5001

CaseService

在您的应用程序组件上,您将调用private caseDataStore = new BehaviorSubject<any>({}); public caseData$ = this.caseDataStore.asObservable(); public GetCaseData(){ const url = environment.api_url; const headers = new Headers(); headers.append('Content-Type', 'application/json'); return this._http.get(url, { headers: headers }) .map(response => { return response.json(); }).toPromise().then(res => { caseDataStore.next(res); }); } 来触发其余呼叫并订阅该主题。

GetCaseData

最后在您的其他组件上,您可以订阅。

public caseData; 
ngOninit() {
    this._caseService.GetCaseData()
  // you can either subscribe and put it into local state, or you can pipe 
  // async into the template directly. 
    this._caseService.caseData$.subscribe( res => {
    this.caseData = res;
}) 
}

UPDADE:详细说明异步管道。

异步管很棒!它是一个方便的助手,允许我们订阅observable而不用担心取消订阅。在我的代码中减少了很多锅炉板。要在示例中使用this._caseService.caseData$.subscribe( res => { this.caseData = res; }) 管道:

而不是在组件上执行此操作

async

你可以在你的html

中拥有这个
 this._caseService.caseData$.subscribe( res => {
        this.caseData = res;
 }) 

但请注意,每次使用 <div> {{ _caseService.caseData$ | async }} </div> 时,都会创建新的订阅。所以以下内容将创建重复订阅。

async

要远离这个,你可以使用

 <div> {{ (_caseService.caseData$ | async)?.prop1 }} </div>
 <div> {{ (_caseService.caseData$ | async)?.prop2 }} </div>
 <div> {{ (_caseService.caseData$ | async)?.prop3 }} </div>

UDPATE 2:如果您已经使用了角度5,请使用httpclient!它会自动将您的REST resposne格式化为JSON。不再需要映射它。

  <div *ngIf="_caseService.caseData$  | async as caseData">
      <div> {{caseData.prop1}} <div>
      <div> {{caseData.prop2}} <div>
      <div> {{caseData.prop3}} <div>
  </div>

我在服务中使用this._http.get(url, { headers: headers }).toPromise().then(res => { caseDataStore.next(res); }); ,因为这是一次性通话,并且不想在之后取消订阅。或者,我见过其他人使用toPromise

更新3:如果您只想对从组件中获取的属性进行选择,则可以从您的可观察对象.first()map

假设您已在联系人组件中使用异步管道。

pluck

现在像往常一样订阅。如果你想进一步迈出这一步!您可以在应用中编写地图管道。

public contactCaseData$ = this._caseService.caseData$.map( data => { 
    return {data.prop1, data.prop2}
}

演示如何运作:https://stackblitz.com/edit/angular-ftxyns?file=app%2Fmap.pipe.ts

答案 1 :(得分:0)

您可以在组件中使用getter

//You can use in your .html
//{{caseData}}

get caseData()
{
    return this._caseService.caseData;
}

另一个想法是订阅您的服务的Observable。 注意:它更好地使用HttpClient而不是#34; old&#34; HTTP