Reputation: 21
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
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
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
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