23

The promise returns a value but I don't seem to be assigning the value properly in the subscribe method.

import { Component } from '@angular/core';
import { DataService } from '../../shared/data.service';

@Component({
  selector: 'topbar',
  templateUrl: './src/app/components/topbar/topbar.component.html',
  styleUrls: ['./src/app/components/topbar/topbar.component.css'],
  providers: [DataService]
})

export class TopbarComponent {
  companyCount;

  constructor (private dataService: DataService){
    dataService.getCompaniesCount().subscribe(res => this.companyCount = res.count); //doesn't work
    dataService.getCompaniesCount().subscribe(res => console.log(res.count)); //works    
  }
}
3
  • What do ypu mean by doesnt work? It works for sure. After assignment check value in console.log(this.companyCount) Commented Sep 15, 2016 at 3:44
  • I think you should be called the getCompaniesCount in ngOnInit() with some code as .subscribe(res => { console.log(res.count); this.companyCount = res.count;}). Commented Sep 15, 2016 at 3:53
  • For future reference if anyone looking into this, you can pass the subscription value to a function to reuse or play with it. Commented Sep 1, 2021 at 4:43

3 Answers 3

18

With this code

export class TopbarComponent {
  companyCount;

  constructor (private dataService: DataService){
    dataService.getCompaniesCount().subscribe(res => this.companyCount = res.count); //doesn't work
    dataService.getCompaniesCount().subscribe(res => console.log(res.count)); //works    
  }
}

res => this.companyCount = res.count doesn't get executed immediately. When getCompaniesCount() makes a request to a server, it takes a long time until the response arrives and the observable calls the function passed to subscribe(...) (res => this.companyCount = res.count).

The execution of the constructor, ngOnInit, ngAfterViewInit() and lots of other stuff will have happened before the response arrives.

You can see

subscribe(res => this.companyCount = res.count)

like registering an event handler that gets called when an event happens.

All code that depends on the data being available needs to be properly chained.

The simplest way is to move to code into subscribe(...)

  constructor (private dataService: DataService){
    dataService.getCompaniesCount().subscribe(res => {
      this.companyCount = res.count); 
      // more code that depends on `res.count` being set goes here
    });
    dataService.getCompaniesCount().subscribe(res => console.log(res.count)); //works    
  }
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the great replies. I'm still learning and new at this. So, the value is being assigned as micronyks suggested and as you say Günter, the issue has to do with the timing of the response. Thank you both for helping me understand that. The problem I think is that the html (topbar.component.html) is trying to consume companyCount before the value is assigned. Is there a best practice that I am missing to solve this problem?
"is trying to consume companyCount before the value is assigned" That's usually the case when data is fetched from the server. You can either wrap the content with <div *ngIf="res?.count">...</div> so that the part within the <div> is not rendered before the data is available or use (as I have already in the *ngIf) the safe-navigation operator. ?. This way the property after .? is only evaluated when the expression before is != null.
@GünterZöchbauer Any other approach to wait for the response to arrive in typescript?
Not sure what you mean. What's wrong with that approach?
4

component context "this" is not available inside of the subscribe(), to fix this, declare _this and assign this before the subscribe() as shown below;

    constructor (private dataService: DataService){
           const _this = this;
           dataService.getCompaniesCount().subscribe(res => {
              this.companyCount = res.count; // does't work
           });
           dataService.getCompaniesCount().subscribe(res => { _this.companyCount = res.count; //works
        });
}

Comments

0

I understand that the thread is old. So, this for the new users who are trying now. I am not sure if this is something that you are looking for. But we can persist data in a component variable albeit an ugly workaround. Here is how we used in a sample POC

(Please use the proper hooks as subsribing to an observable is not preferred in a constructor)

        @Component({
  selector: 'app-search-promo',
  templateUrl: './search-promo.component.html',
  styleUrls: ['./search-promo.component.css']
})
export class SearchPromoComponent implements  AfterViewInit {
  searchGroup: FormGroup;
  stringify  =  require('json-stringify-safe');
  someResult:any;
  resp:Response;
  localInput = new FormControl('', Validators.required);
  consumedPromoList: Observable<Promotion[]>;
  constructor(private searchService: SearchService, fb: FormBuilder) {
    this.searchGroup = fb.group({
      'localInput': this.localInput
    });
     this.stringify = require('json-stringify-safe');
     this.searchService.getPromoList().subscribe(
       resp => {
         this.someResult = <Promotion[]>resp;
         console.log("Inside sub in comp"+this.stringify(resp));
         console.log("before calling the methid");
         this.callDto(<Promotion[]>resp);
       }
     );
     console.log('inside const()' + this.stringify(this.someResult));
   }

callDto(data){
    console.log("caling"+data);
    this.someResult = <Promotion[]>data;
    console.log("Now priting:"+this.someResult);
    this.anotherMethod();
  }

  anotherMethod(){
    console.log("Inside another method"+this.stringify(this.someResult));
  }
}

That was the sample component and below is the sample service

@Injectable()
export class SearchService {
  getUrl: String = './../assets/promotionList.json';
  subject: BehaviorSubject<Promotion[]> = new BehaviorSubject([]); // initialize with an empty response[]
  subjectAsObservable;
   someResult;
   promoList:Promotion[];
  constructor(private http: HttpClient) {
    this.getPromoList();
    console.log("after first");
    this.getPromoValues();
    console.log("after second call");
  }

    getPromoList(){
    // by default it emits a response of Json and hence Observabpe<PromotionList>
    // throws an error
    this.someResult = this.http.get(`${this.getUrl}`);
    console.log("before map"+<Observable<Promotion[]>> this.someResult);
    return (<Observable<Promotion[]>> this.someResult);
    //console.log("first subsriber"+JSON.stringify (this.someResult);

  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.