Need help chaining subscribes [MOSTLY RESOLVED]

I’m creating an Ionic2 app that, from the start, is localized. Content within pages (HTML) was easy to handle using pipes. I realized, though, that for my side menu I needed to perform my translations in advance. The little code below works but, to me, is unwieldy. Any suggestions for helping me chain my subscribe events?

My goal is to use the subscription associated with the translation service and to setup my sidebar titles only after I’ve retrieved all my translated values.

translate.use(language);

let side_titles:any = {};

translate.get('APP.SIDE_TITLE_ARRIVALS').subscribe(
  value => { side_titles['Arrival Info'] = value; },
  error => { console.error('Error: ' + error.message) },
  () => {

    translate.get('APP.SIDE_TITLE_CONTACTS').subscribe(
      value => { side_titles['Contacts'] = value; },
      error => { console.error('Error: ' + error.message) },
      () => {

        translate.get('APP.SIDE_TITLE_RIGHTS').subscribe(
          value => { side_titles['Rights'] = value; },
          error => { console.error('Error: ' + error.message) },
          () => {

            translate.get('APP.SIDE_TITLE_LOCALINFO').subscribe(
              value => { side_titles['Local'] = value; },
              error => { console.error('Error: ' + error.message) },
              () => {

                translate.get('APP.SIDE_TITLE_HELP').subscribe(
                  value => { side_titles['Help'] = value; },
                  error => { console.error('Error: ' + error.message) },
                  () => {

                    translate.get('APP.SIDE_TITLE_ABOUT').subscribe(
                      value => { side_titles['About'] = value; },
                      error => { console.error('Error: ' + error.message) },
                      () => {
                        this.setupSideBar(side_titles);
                      });
                  });
              });
          });
      });
  });

  setupSideBar (side_titles) {
    // used for an example of ngFor and navigation
    this.pages = [
      { title: side_titles ['Arrival Info'], component: ArrivalsPage },
      { title: side_titles ['Contacts'], component: ContactsPage },
      { title: side_titles ['Rights'], component: YourRightsPage },
      { title: side_titles ['Local'], component: LocalInfoPage },
      { title: side_titles ['Help'], component: HelpPage },
      { title: side_titles ['About'], component: AboutPage }
    ];
    
  }

I think I figured out one approach, though I’m not super excited because it seems like I’m still hardcoding things. I’d rather have this driven off an array of values and targets. Here’s what I’ve got so far - and it seems to work. Still, I’d like to hear from smarter people than myself on alternative or better patterns.

   Observable.forkJoin (
    translate.get ('APP.SIDE_TITLE_ARRIVALS'),
    translate.get ('APP.SIDE_TITLE_CONTACTS'),
    translate.get ('APP.SIDE_TITLE_RIGHTS'),
    translate.get ('APP.SIDE_TITLE_LOCALINFO'),
    translate.get ('APP.SIDE_TITLE_HELP'),
    translate.get ('APP.SIDE_TITLE_HELP'),
   ).subscribe (
     data => {
       side_titles['Arrival Info'] = data[0];
       side_titles['Contacts'] = data[1];
       side_titles['Rights'] = data[2];
       side_titles['Local'] = data[3];
       side_titles['Help'] = data[4];
       side_titles['About'] = data[5];
     },
     err => console.error (err),
     () => {
       console.log ('Done');
       console.log (JSON.stringify (side_titles));
     }
   )

Do you know about and have you looked at https://ionicframework.com/docs/resources/ng2-translate/?

Yes. That’s specifically what I used to get to the point I’m at. That article, though, doesn’t address asynchronous chaining of observables. However, now that I’m going back over the article it seems there’s an option to pass in an array of keys. Will explore that more, now.

Ok - this mechanism does what I need without having to do any special chaining. Though, I’d still like to learn how to chain observables more effciently.

  let names = [
  'APP.SIDE_TITLE_ARRIVALS',
  'APP.SIDE_TITLE_CONTACTS',
  'APP.SIDE_TITLE_RIGHTS',
  'APP.SIDE_TITLE_LOCALINFO',
  'APP.SIDE_TITLE_HELP',
  'APP.SIDE_TITLE_HELP'
];

translate.get (names).subscribe (
  data => {
    console.log (JSON.stringify(data));
  },
  e => console.error (e),
  () => {
    console.log ('Done');
  }
);
1 Like

Use it like this:

let localization: any = [];

constructor(public translate: TranslateService) {
	translate.get('APP').subscribe(values => {
		// values is our translations
		this.localization = values;
	});
}

setupSideBar() {
	this.pages = [
		{ title: this.localization.SIDE_TITLE_ARRIVALS, component: ArrivalsPage },
		{ title: this.localization.SIDE_TITLE_CONTACTS, component: ContactsPage },
		{ title: this.localization.SIDE_TITLE_RIGHTS, component: YourRightsPage },
		{ title: this.localization.SIDE_TITLE_LOCALINFO, component: LocalInfoPage },
		{ title: this.localization.SIDE_TITLE_HELP, component: HelpPage },
		{ title: this.localization.SIDE_TITLE_ABOUT, component: AboutPage }
	];
}

I don’t know how to chain observerables. However, this is an approach for promises.

If you don’t care about the promises to be completed asynchronously:

let chain = [this.asyncFunction(), this.asyncFunction(), this.asyncFunction()];

Promise.all(chain).then((results: any) => {
    // do something with results
});

If you want promises to be completed synchronously:

// initatiate the chain
let chain = Promise.resolve();

// create 10 chain items
for(let i = 0; i < 9; i++){
	let chainItem = function() {
		return new Promise((resolve, reject) => {
			// do someting async stuff
			// resolve or reject it (return stops the code at that point)
			if(OK){
				return resolve();
			} else {
				return reject();
			}
		});
	}

	chain = chain.then(chainItem);
}

// do something with the chain result
chain.then((success: any) => {
    console.log(success);
}, (error: any) => {
    console.log(error);
});