alexx0118
alexx0118

Reputation: 21

How to change my promise to an observable?

I have a service with a selectedLanguage variable, but I got a null value instead of the real value

data: any = {};
  selectedLanguage = 'en';
  constructor(private http: HttpClient, private storage: Storage) {
  }

  async use(lang: string): Promise<{}> {
    lang = lang ? lang : await this.storage.get('lang');
    return new Promise<{}>((resolve) => {
      const langPath = `assets/i18n/${lang || 'en'}.json`;
      this.selectedLanguage = lang;
      this.storage.set('lang', this.selectedLanguage);
      this.http.get<{}>(langPath).subscribe(
        translation => {
          this.data = Object.assign({}, translation || {});
          return resolve(this.data);
        },
        () => {
          this.data = {};
          return resolve(this.data);
        }
      );
    });
  }

  get(): string {
    return this.selectedLanguage;
  }
}

In the component.ts file i use it but not in a good way

export class LoginComponent implements OnInit {
  imgError = false;
  loginForm: FormGroup;
  selectedLanguage: string;




  constructor(
    public storage: Storage,
    private translateService: TranslateService,
    private alertController: AlertController,
    private translate: TranslatePipe
  ) { }

  ngOnInit() {
    this.selectedLanguage = this.translateService.selectedLanguage;

How can I use selectedLanguage as an observable to not get a null value?

Upvotes: 0

Views: 3806

Answers (3)

Jonathan Stellwag
Jonathan Stellwag

Reputation: 4267

You can create a new Observable thats observer receives the value of your Promise.

const { Observable } = rxjs;

const promise$ = new Promise(resolve => resolve('Success!'))

const observable$ = new Observable(observer => promise$.then(value => observer.next(value)))

observable$.subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js"></script>

Step by Step:

The Promise is created and the value Success! is directly resolved. Also a Observable is created and the body of the observer-function listens for a value of the Promise.

Why do we get an value although the Promise was set and resolved before the Observable was created?

Promises are not synchronously processed. They are microtasks. Those are processed after makrotasks. RxJS by default uses a Scheduler to process each value that goes through its pipes/operators/functions. The default scheduler (you can read it at the bottom of the link) is an asyncScheduler that is internal some kind of setTimeout mechanism and therefore a makrotask.

Sum:

The Observable receives the value of the Promise as its processed before the Promise value.

Its a complicated topic. The mikro- and markotask stuff relates to the JavaScript Event Queue. This youtube video explained it very well to me.

Upvotes: 1

Dariusz
Dariusz

Reputation: 314

some example how to set language with observables is below

   setLang(lang: string): Observable<void> {
        return fromPromise(this.storage.get('lang')).pipe(flatMap((lang) => {
            const langPath = `assets/i18n/${lang || 'en'}.json`;
            return this.http.get<{}>(langPath)
        }), map(data => {
            return ...doSomeDataMapping
        }), tap((result) => {
            this.data = result;
            this.selectedLanguage = lang
        }))
    }

tap part is needed only if you really need to have stateful service.

If You need async getter for selected language field your tap will look like below :

 tap((result) => {
            this.data$.next(result);
            this.selectedLanguage$.next(lang)
        })

and you'll need :

private data$ = new BehaviorSubject(initialValue);
private selectedLanguage$ = new BehaviorSubject(initialValue);

at the top.

then getters will be

    getSelectedLanguage$(): Observable<string> {
        return this.selectedLanguage$;
    }

called in component

this.selectedLanguage$ = this.translateService.getSelectedLanguage$();

and used with async pipe in view for example

Upvotes: 0

Venkatesh K
Venkatesh K

Reputation: 153

Just declare a method that returns observable. In your ngOnInit(), call this method and onSubscription you can would get the value. Once your method execution is completed return observable value. I've given a sample code. You can check this link to get more info.

get(langObtained): Observable<String> {
    let lang= langObtained;
    return of(lang);
  } 

ngOninit(){
   this.get('hi').subscribe(response=>{
//use the response
    });
}

Upvotes: 0

Related Questions