oxid2178
oxid2178

Reputation: 45

Binding a spinner href method in nav bar to a view-model to publish a message for subscriber

I'm trying to implement a web application with aurelia and TypeScript. I started from the aurelia-skeleton-typescript-webpack project as basis.

In the nav-bar I have also inserted a spinner for choose various city location, which should call a method which in turn publishes a message so that in the app.js a subscriber should display the view of the corresponding city.

I have implemented the view nav-bar-spinner.html and the view-model nav-bar-spinner.ts, which creates the spinner in the view nav-bar.html. The nav-bar.html is then inserted in the app.html as a template. Each spinner item has a method that calls the publishLocation('city'), which are bound with the view-model nav-bar-spinner.ts.

Now when I click on a spinner item I receive the error:

"Error: publishNavLocation is not a function"

I thing is a binding problem. I make a custom instantiation from object nav-bar-spinner in app.ts.

How can I do this binding correct? I would be glad for some tips.

Here the code:

app.html

<template>
  <require from="nav-bar.html"></require>
  
  <nav-bar router.bind="router"></nav-bar>

  <div class="page-host">
    <div class="row">
       <router-view swap-order="after" class="col-md-12"></router-view> 
    </div>
  </div>

</template>

app.ts

import {Redirect} from 'aurelia-router';
import {Router, RouterConfiguration} from 'aurelia-router';
import {EventAggregator} from 'aurelia-event-aggregator';
import {inject} from 'aurelia-framework';
import {NavBarSpinner} from './nav-bar-spinner';

@inject(EventAggregator)
export class App 
{
    
  navBarSpinner;

  constructor(private ea: EventAggregator) 
  {
      this.navBarSpinner = new NavBarSpinner('hello world')
  }

  router : Router;

  configureRouter(config: RouterConfiguration, router: Router) 
  {
    config.title = 'bbv AmbientMonitor';
    config.map([
      { route: '',                name: 'login',           moduleId: './login',            nav: true,  title: 'Anmeldung' },
      { route: 'live-view-all',   name: 'live-view-all',   moduleId: './live-view-all',    nav: true,  title: 'Live-Ansicht' },
      { route: 'live-view-zg',    name: 'live-view-zg',    moduleId: './live-view-zg',     nav: true,  title: 'Live-Ansicht' },
      .
      .
      .
      .
      .
      .
      { route: 'historical-view', name: 'historical-view', moduleId: './historical-view',  nav: true,  title: 'Historie-Ansicht'}
    ]);

    this.router = router;
  }
  
  attached() 
  {
      this.ea.subscribe('nav::toggleLogin', (data) => 
      {
        console.log('Subscribe data is: ' + data.nav);
        this.router.navigateToRoute(data.nav);
      });
  }
}

nav-bar.html

<template bindable="router">
    <require from="./nav-bar-spinner"></require>
        <!-- <require from="nav-bar-spinner.html"></require> -->
      <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#skeleton-navigation-navbar-collapse">
            <span class="sr-only">Toggle Navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">
            <i class="fa fa-home"></i>
            <span>${router.title}</span>
          </a>
        </div>
    
        <div class="collapse navbar-collapse" id="skeleton-navigation-navbar-collapse">
        
          <ul class="nav navbar-nav">
            <div class="pull-left">
              <compose class="nav navbar-nav" view="nav-bar-spinner.html" view-model.bind="navBarSpinner"></compose>
            </div>
            <li repeat.for="row of router.navigation" class="${row.isActive ? 'active' : ''}">
              <a data-toggle="collapse" data-target="#skeleton-navigation-navbar-collapse.in" href.bind="row.href">${row.title}</a>
            </li>
          </ul>
    
          <!-- <ul class="nav navbar-nav navbar-right">
            <li class="loader" if.bind="router.isNavigating">
              <i class="fa fa-spinner fa-spin fa-2x"></i>
            </li>
          </ul> -->
        </div>
      </nav>
    </template>

nav-bar-spinner.html

<template bindable="navBarSpinner">
    <li class="dropdown">
    <div as-element="compose" view-model.bind="navBarSpinner"></div>
    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Standort <span class="caret"></span></a>
      <ul class="dropdown-menu">
            <li><a href="#" click.trigger="publishNavLocation('live-view-zg')">Zug</a></li>
            <li><a href="#" click.trigger="publishNavLocation('live-view-zh')">Zürich</a></li>
            <li><a href="#" click.trigger="publishNavLocation('live-view-be')">Bern</a></li>
            <li><a href="#" click.trigger="publishNavLocation('live-view-lu')">Luzern</a></li>
            <li><a href="#" click.trigger="publishNavLocation('live-view-mu')">München</a></li>
      </ul>
    </li>
</template>

nav-bar-spinner.ts

import { EventAggregator } from 'aurelia-event-aggregator';
import { inject } from 'aurelia-framework';
import { View } from "aurelia-framework";

@inject(EventAggregator)
export class NavBarSpinner {
    
    ea;

    constructor(msg) {
        this.ea = new EventAggregator();
    }

    publishNavLocation(navToCity) {
        this.ea.publish('nav::toggleLogin', {nav: navToCity});
        console.log("Method call publishLocationZug()");
    }
}

Upvotes: 0

Views: 153

Answers (2)

oxid2178
oxid2178

Reputation: 45

Thanks for the tips. After reading better the aurelia doc i resolved my problem. Here my changes for typescript:

Chanded inject with autoinject

import { autoinject } from 'aurelia-framework';`
-
-
-
@autoinject( EventAggregator )
export class NavBarSpinner {
    constructor(private ea: EventAggregator) {}
-
-
-

and in nav-bar.html i inserted the nav-bar-spinner.html with the binding view-model="nav-bar-spinner"

<div class="pull-left">
  <compose class="nav navbar-nav" view-model="nav-bar-spinner"></compose>
</div>

and removed the other unnecessary bindings and requirements.

Upvotes: 0

Jesse
Jesse

Reputation: 3622

Your problem lies with the following line:

view-model.bind="navBarSpinner"

Aurelia doesn't process this correctly. It is the name of the class, but you need to address it differently in an HTML attribute.

view-model.bind="nav-bar-spinner"

This tells Aurelia to look for a class named NavBarSpinner.

P.S. I also recommend you look into how Aurelia Dependency Injection works, you have quite some unnecessary (and false) code right now.

Upvotes: 0

Related Questions