Aurelia - Trouble with custom-element

2019-08-26 03:22发布

问题:

Novice.

I have an app.html that has two custom-elements:

<template>
    <require from="../navmenu/navmenu.html"></require>
    <require from="./app.css"></require>
    <!--We want the nav bar to span the page-->
    <div class="container-fluid">
        <navmenu router.bind="router"></navmenu>
    </div>
    <!--We want the media to centre so we use just container-->
    <div class="container">
        <div className='col-sm-12'>
            <div className='row'>
                <router-view></router-view>
            </div>
        </div>
    </div>
</template>

The router is bound to the navmenu and so I have routing.

Because I have the following require with the extension .html:

<require from="../navmenu/navmenu.html"></require>

I do not have access to my viewmodel.

If I change the require by removing the .html I loose all my navbar items.

My navbar.ts is:

import { autoinject, bindable, bindingMode } from "aurelia-framework";
import { LoggedInService } from "../components/auth/LoggedInService";
import { customElement } from "aurelia-templating";

@autoinject
@customElement('navmenu')
export class Navmenu {

    @bindable public isLoggedIn: boolean = false;
    @bindable public userName: string = 'anonymous';

    constructor(public loggedInService: LoggedInService) {
        this.isLoggedIn = loggedInService.isAuthenticated();
        this.userName = loggedInService.getUserName();
    }
}

I have added "@binding" to the two variables I want to use but I have no access to them. I have looked at the guide for custom-elements but they are indicating I need to import

How do I access those variables without screwing up my navbar items? or..

How do I access the navmenu viewmodel when the view has been referenced with ".html".

Here is my navmenu.html:

<template bindable="router">
    <require from="./navmenu.css"></require>
    <div class="main-nav">
        <div class="navbar navbar-inverse">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".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="#/home">Jobsledger.API</a>
            </div>
            <div class="navbar-collapse collapse">

                <ul class="nav navbar-nav">

                    <li repeat.for="row of router.navigation" class="${ row.isActive ? 'link-active' : '' }">
                        <a href.bind="row.href" if.bind="!row.settings.nav">${ row.title }</a>

                        <a href.bind="row.href" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"
                           if.bind="row.settings.nav">
                            ${row.title}
                            <span class="caret"></span>
                        </a>

                        <ul if.bind="row.settings.nav" class="dropdown-menu">
                            <li repeat.for="menu of row.settings.nav">
                                <a href.bind="menu.href">${menu.title}</a>
                            </li>
                        </ul>
                    </li>
                </ul>
            </div>
        </div>
    </div>
    LoggedIn Value: ${ isLoggedIn }
</template>

回答1:

you need to load your navbar as

<require from="../navmenu/navmenu"></require>

and inject your router to viewmodel

import { autoinject, bindable, bindingMode } from "aurelia-framework"
import { LoggedInService } from "../components/auth/LoggedInService"
import { Router } from 'aurelia-router'

@autoinject
export class NavMenu {
    loggedInService: LoggedInService
    router: Router

    @bindable isLoggedIn: boolean = false
    @bindable userName: string = 'anonymous'

    constructor(loggedInService: LoggedInService, router: Router ) {
        this.isLoggedIn = loggedInService.isAuthenticated()
        this.userName = loggedInService.getUserName()
        this.router = router
    }
}

remove bindable="router" from <template> tag

you can also make router another @bindable in your viewmodel where you dont need to inject Router, but that's for you to try if the above doesnt work for you.



回答2:

You have to import the viewmodel if you want to use any javascript, so in your case, using <require from="../navmenu/navmenu"></require> is the correct approach.

I think you have misunderstood the meaning of @bindable(). @bindable() means that you can bind that value when you create the element, like so:

<navmenu username.bind="user.name"></navmenu>

Any property declared as public in your viewmodel can be accessed by your view:

export class Navmenu {

    public isLoggedIn: boolean = false;
    public userName: string = 'anonymous';

    constructor(public loggedInService: LoggedInService) {
        this.isLoggedIn = loggedInService.isAuthenticated();
        this.userName = loggedInService.getUserName();
    }
}

<template>
  <span>${userName} is logged in: ${isLoggedIn}</span>
</template>

If you want to inject your router into your viewmodel, you shouldn't use viewmodel binding like you did in your example. You can simply inject the router using dependency injection:

import { Router } from "aurelia-routing";
import { autoinject } from "aurelia-framework";
import { LoggedInService } from "../components/auth/LoggedInService";
import { customElement } from "aurelia-templating";

@customElement('navmenu')
@autoinject()
export class Navmenu {

        public isLoggedIn: boolean = false;
        public userName: string = 'anonymous';

        constructor(
            public loggedInService: LoggedInService,
            public router: Router) {
            this.isLoggedIn = loggedInService.isAuthenticated();
            this.userName = loggedInService.getUserName();
        }
    }

And then access it in your viewmodel and/or view.



回答3:

you need to add a bindable router to your viewmodel

import { bindable, autoinject } from "aurelia-framework";
import { Router } from 'aurelia-router';

export class navmenuCustomElement {
@bindable router: Router;
}