Ionic2 navigation & circular depencies

Hey all, I am trying to get my head around navigation in ionic2. I am trying to have a list directive, that on item click will go to a details page. That details page unfortunately also has a list itself.

My understanding of the Navigation is that I will have to pass a type of page into NavController.push(…). Therefore I will have to import that “Page class” in my List definition.
The details page, if it wants to use the list directive, will have to have an import to the list directive. Therefore I will have to place a dependency on the list which closes the circle (listItems <-> detailsPage). When I try to run this code it blows up, saying it can’t find the output for the itemList, which I guess comes from the circle keeping it from compiling.

I have pushed a small example app on https://github.com/AndreasMaier/ionic2_nav.git which should just run with npm install && ionic serve (if you have ionic@beta)

Basically the important files are pages/details/details.ts and directives/listItems.ts.

I haven’t found too many examples of the navigation, so I would be happy about any ideas on how to solve this or a direction to look into concerning ionic2 navigation.

The circular navigation isn’t an issue since the navigation is really just a FIFO stack. No matter how you conceptually have your page linkages setup, to ionic, it just has one direction it cares about, back to the previous page.

It sounds like the issue you’re running into is attempting to have 2 different files depend on each other. No matter which file the system picks first, it will always be missing dependencies in the other file, or loop until it overflows and crashes.

If you restructure the data model to not have dependencies on either controller, then both your controllers can depend on the data model. The last piece is how does one controller know about the other. I’m still new to angular, so my ability to provide a specific answer here is limited, but in other languages like python, I’d have my dependency to the other controller referenced inside the click action itself, and thus allow the code to compile.

I’m guessing that doing a bit of googling for controllers calling each other will yield a successful program.

Hope this helps,
Orby

Thanks for your reply Orby. What do you mean by FIFO stack? Or do you just mean a standard stack (LIFO) ? That would make sense for the backwards functionality.

However in angular 1 for example you would have $state to navigate around, which would just take route names (strings). By that you don’t introduce any dependencies on other pages/controllers directly (except that something should fulfill the route contract).

I am aware why circular deps don’t work in typescript. I am looking for a way to solve this and still being able to use the NavController (suggested in the ionic2 tutorial), so that the whole backwards functionality is preserved.

My apologises it is a LIFO, not FIFO.

I found this directive used inside views. This might work in your case.

Looking at the answers in this post, there is no way to have both classes know about each other:

It would be handy for the NavController.push() to accept a string name, I don’t see any indication that it does.

-Orby

What I did to solve the circular import problem:
Each of the @Pages can invoke each other, by passing a string name to this NavigationService.

The Navigation service, get’s around the circular import by late binding, using require() directly.

Presumably you could do this in each @Page, but I find this a cleaner solution. Also the closeMenu implements a hack to close slideout menus if they hapen to be open (a bug in earlier versions of Ionic2)

import {IonicApp} from 'ionic-framework/ionic';
import {Injectable} from 'angular2/core';

@Injectable()
export class NavigationService {
pages = {};
constructor(private app: IonicApp) {
    this.pages['imageGrid'] = require('../pages/img-grid/img-grid').ImageGrid;
    this.pages['templateGrid'] = require('../pages/template-grid/template-grid').TemplateGrid;
    this.pages['articleSelect'] = require('../pages/article-select/article-select').ArticleSelect;
    this.pages['imageEdit'] = require('../pages/img-edit/img-edit').ImageEdit;
}

closeMenu() {
  this.app.getComponent('leftMenu').close();
  setTimeout(() => {
    console.log('deactivating background');
    document.getElementsByClassName('backdrop')[0]['style']['transform'] = '';
   }, 1000);
}

rootPage(page:string, params?: {}) {
  let nav = this.app.getComponent('nav');
  if (nav) {
    nav.setRoot(this.pages[page]);
  }
  this.closeMenu()
 }
nextPage(page: string, params?: {}) {
  let nav = this.app.getComponent('nav');
  if (nav) {
    nav.push(this.pages[page], params);
  }
  this.closeMenu()
}
}

This is awesome! I’m seeing that the ionic navigation system, while very intuitive and easy to use, lends itself to lots of headaches with circular dependencies as your app gets larger. So it would be tough to build larger, more complex apps without some work arounds some how.

As of ionic 2.2.0, you IonicApp doesn’t give you all that it used to. So I’m using the following:

import { App } from from 'ionic-angular';

rootPage(page:string, params?: {}) {
     this.app.getRootNav().setRoot(this.pages[page], params);
 }

nextPage(page: string, params?: {}) {
  this.app.getRootNav().push(this.pages[page], params);
}

closeMenu isn’t needed.