Best practices to call functions from Navigation?

I am working on an ionic / angular application that had a top navigation bar to handle my back and continue routes. I set the route dynamically in the routing module based on where i am and where i want to go.

I am trying to add a form submit to the continue in my navigation and I am really struggling with the best way of doing that across the components.

Here is what my app.component looks like

<ion-app>
  <stm-navbar></stm-navbar>
  <stm-loader></stm-loader>
  <ion-router-outlet main></ion-router-outlet>
</ion-app>

My navigation looks something like this. If the route is defined i set the route link, and the 2nd one was what i was trying to do with the click handler

      <a
        id="aNavRightRoute"
        *ngIf="navbarRightRoute"
        [routerLink]="navbarRightRoute.path + (this.itemId ? '/' + this.itemId : '')"
        [ngClass]="navbarRightRoute.class"
        >Continue</a
      >
      <a
        id="aNavRightClick"
        *ngIf="navbarRightClick"
        [ngClass]="navbarRightClick.class"
        (click)="this[navbarRightClick.click]()"
        >Continue</a

I am able to get the function to be called if I have it in my typescript of the navigation, but I cannot figure out how to fire it in the page that i have been navigated to. Those properties are defined in my routing module like so

{
        path: 'new-page',
        component: NewPageComponent,
        data: {
          navbarTitle: 'Nav Title',
          navbarLeftButton: {
            back: true
          },
          navbarRightClick: {
            click: 'someFucntion'
          }
        }
      }

I am just trying to submit a form on continue click. I have thought about just firing an ionic event from the navigation, but i know there must be a better way to handle this. It seems like common practice to need a click handler in your generic navigation.

Any tips would be appreciate on how to do this or if there is a better way.

Virtually every time I have found myself asking “how do I call a function in there from here?” in an Angular app, it turned out that really wasn’t what I wanted to do. What I wanted instead was “how do I respond to something changing or happening in there?”, combined with “how do I register a change or happening over here?”. Combined with the fact that there are (or at least have been) some rough edges involving passing navigation parameters that are not just scalars, I treat navigation as just a way of controlling what page is active in the app. For stuff like you are aiming at here, my first instinct is to use an Observable in a mutually injected service, but you lost me at “I want to submit a form on continue click”.

Where is the form? In the current page? In the new page? What do you mean by “submit”?

thanks for the reply

When I say “submit the form” i simply mean call a function in the page that is loaded in the ion-router-outlet. I see examples of parent / child function calls, but i am not sure if its even possible because the nav-bar is a component of my ion-app as you can see from the code above

I can’t think of a situation where I would write things that way. A situation I have encountered which may map onto yours (I still don’t really understand what you are trying to do in “explain it to a 5-year-old” terms) is what I would call a contextual action: a button in a toolbar that causes stuff to happen in places that it can’t anticipate. The way I handle this looks fundamentally like so:

class Action<T> {
  private feed$ = new BehaviorSubject<T | null>(null);
  watch(): Observable<T | null> { return this.feed$; }
  trigger(payload: T | null): void { this.feed$.next(payload); }
}

class Actions {
  frotzer = new Action<void>();
}

class Toolbar {
  constructor(public actions: Actions) {}
}

<ion-button (click)="actions.frotzer.trigger()">frotz</ion-button>

class Frotzable {
  constructor(private actions: Actions) {}
  ngOnInit(): void {
    this.actions.frotzer.watch().pipe(untilDestroyed(this))
      .subscribe(() => this.frotzLiberally());
  }
  ngOnDestroy(): void {}
  frotzLiberally(): void {
    // gets called when toolbar frotzer button is clicked
  }
}

There’s some more magic that automatically enables and disables the button depending on whether anybody’s subscribed to it or not, but this is the basic idea, and maybe it will be of use to you.

Damn it… wish I wasn’t butchering this so much… i am still a n00b, so that could be a lot of my problem.

Me try to explain in words.

  1. I have a nav bar that is always present at the top and thats the stm-nav component which is set in the ion-app. That navbar’s template is defined with data from the routing module. For example, is the back button present or not or if there is a forward botton, a url is pass for the router link of the .

  2. One of my pages that is now loaded from a route has an ion-input which takes in say a name. I need to be able to click continue in the navbar and have my page know that the continue has been clicked so i can perform some operation within that page. Validate the name and then call a service to make an api call with the value of name.

Where I am getting hung up is that this all worked fine with routelinks being set in the router module, but now that I am trying to set a click event in the routing module, i don’t have a clue how to do that and have that click call a function from within the page.

Let me explain how i have it working which might also help with what i am trying t accomplish.

  1. I have added a click event that calls a function within my navbar compoent and takes a string from the routing module. That function fires an ionic event with the string defined for that page.

  2. My page with the inout subscribes to that event and performs the function

I think that’s more or less the “contextual action” implemented in my previous post.

Here I fear we perhaps may have a philosophical difference. I endeavor to minimize dependencies amongst actors in my code, because in my experience that tends to be where bugs lie, and I have a harder time documenting, maintaining, and testing code where (for example) a navbar’s template is affected by anything outside navbar-world. I want my navbar’s job to be “telling the world that stuff got clicked”, with nary a care for how other parts of the app might interpret that.

I think that sounds more or less like my contextual action button, except I’m using direct Observables instead of Ionic Events because reasons and death.

I guess basically what I’m saying is that while you might be able to shoehorn this functionality into navigation, it doesn’t feel to me very navigatory, so maybe after all it’s better off separate.

Does that make any sense?