web-dev-qa-db-fra.com

emberjs - comment marquer un élément de menu actif en utilisant une infrastructure de routeur

J'essaie de créer des onglets de navigation (extraits de Twitter Bootstrap ):

<ul class="nav nav-tabs">
    <li class="active"><a href="#">Home</a></li>
    <li><a href="#">Profile</a></li>
    <li><a href="#">Messages</a></li>
</ul>

L'onglet actif est marqué avec class="active".

Il existe un excellent exemple de fonction de barre de navigation statique et de routeur/prise à l'adresse http://jsfiddle.net/schawaska/pfbva/ , mais Je ne comprends pas comment créer une vue dynamique de barre de navigation/menu/onglet .

Autant que je sache, il est possible d'utiliser des liaisons de classe dans chaque élément de menu:

 classNameBindings: ['isActive:active']

Mais où est le bon endroit pour changer les attributs isActive?

51
coxx

Si vous utilisez Ember> = 1.11, alors https://stackoverflow.com/a/14501021/65542 ci-dessous est la bonne réponse.


Je créerais un NavigationView, voir http://jsfiddle.net/pangratz666/z8ssG/ :

Guidon:

<script type="text/x-handlebars" data-template-name="navigation">
    <ul class="nav nav-tabs">
        {{#view view.NavItemView item="home" }}
            <a {{action gotoHome}} >Home</a>
        {{/view}}
        {{#view view.NavItemView item="profiles" }}
            <a {{action gotoProfiles}} >Profiles</a>
        {{/view}}
        {{#view view.NavItemView item="messages" }}
            <a {{action gotoMessages}} >Messages</a>
        {{/view}}        
    </ul>
</script>

JavaScript:

App.NavigationView = Em.View.extend({
    templateName: 'navigation',
    selectedBinding: 'controller.selected',
    NavItemView: Ember.View.extend({
        tagName: 'li',
        classNameBindings: 'isActive:active'.w(),
        isActive: function() {
            return this.get('item') === this.get('parentView.selected');
        }.property('item', 'parentView.selected').cacheable()
    })
});

Et à l'intérieur de connectOutlets de votre route, vous devez définir l'élément de navigation actuel via router.set('navigationController.selected', 'home'); ...


Jetez également un coup d'oeil au répertoire ember-bootstrap qui englobe tout cela, ainsi que d'autres fonctionnalités de Bootstrap dans Ember.js

26
pangratz

Ember 1.11+:

{{#link-to "dashboard" tagName="li"}}
  <a href="{{view.href}}">Dashboard</a>
{{/link-to}}

Ember <1.11 (bind-attr requis):

{{#link-to "dashboard" tagName="li"}}
  <a {{bind-attr href="view.href"}}>Dashboard</a>
{{/link-to}}
154
lesyk

Certaines des suggestions ci-dessus sont toujours valables pour le cas de démarrage de Twitter. Vous pouvez aussi essayer quelque chose comme ça

{{#link-to 'dashboard' tagName='li'}} 
  {{#link-to 'dashboard'}}Link Title{{/link-to}}
{{/link-to}}
  1. Le link-to avec li tagName applique la classe active au li
  2. Le link-to interne serait un élément anchor qui vous donne la fonctionnalité Open in New Tab lorsque vous cliquez avec le bouton droit de la souris
17
selvagsz

Un addon Ember-cli est récemment disponible. Il s'appelle ember-cli-active-link-wrapper .

Installer: ember install ember-cli-active-link-wrapper

Vous pouvez l'utiliser comme ceci:

{{#active-link}}
  {{link-to "Index" "index"}}
{{/active-link}}

qui se traduit par:

<li class='active'>
    <a href="/" class='active'>Index</a>
</li>
10
Willem de Wit

Je sais que c’est un vieux message, mais voici des mises à jour pour Ember 2.4.0

Pour créer des liens, vous pouvez écrire

{{#link-to 'photoGallery'}}
  Great Hamster Photos
{{/link-to}}

ou

{{link-to 'Great Hamster Photos' 'photoGallery'}}

Ember définira automatiquement la classe sur active lorsque la route actuelle correspond à la route de link (dans cet exemple photoGallery).

Si vous souhaitez également contrôler la classe 'active' sur d'autres routes, vous pouvez le faire en définissant l'attribut current-when.

{{#link-to 'photoGallery' current-when='photoGallery photoPreview'}}
  Great Hamster Photos
{{/link-to}}

Ce lien aura la classe active sur les routes photoGallery et photoPreview.

https://github.com/emberjs/ember.js/blob/v2.4.0/packages/ember-routing-views/lib/components/link-to.js#L140

7
Ivan Bajalovic

Guidon

<ul class="nav">
    <li>{{#linkTo "index"}}Index{{/linkTo}}</li>
    <li>{{#linkTo "about"}}About{{/linkTo}}</li>
</ul>

Javascript

App.Router.map(function() {
    this.route("about");
});

Il ajoutera automatiquement une classe active en fonction de la route .

4
ketan

Je vois que cette question est assez ancienne, mais si vous mettez à niveau Ember.js vers le RC3, vous pouvez utiliser la propriété tagName, comme:

{{#link-to messages tagName="li"}}Messages{{/link-to}}

Voici l'API - http://emberjs.com/api/classes/Ember.LinkView.html

3
Wojciech Bednarski

Vous pouvez également changer la méthode isActive en quelque chose comme ceci:

isActive: function() {
    return App.getPath('router.currentState.path') === "root.firms";
}.property("App.router.currentState"),

ou

isActive: function() {
    return this.get('controller.target.currentState.path') === "root.firms";
}.property("controller.target.currentState"),
3
pjlammertyn

Pas sûr que ce soit très dynamique, mais essayez de voir la solution sur http://codebrief.com/2012/07/anatomy-of-an-ember-dot-js-app-part-i-redux-routing-and- points de vente/ L'idée principale est de vérifier l'état de votre application

JavaScript:

function stateFlag(name) {
  return Ember.computed(function() {
    var state = App.router.currentState;
    while(state) {
      if(state.name === name) return true;
      state = state.get('parentState');
    }
    return false;
  }).property('App.router.currentState');
}

ApplicationController: Ember.Controller.extend({
    isHome: stateFlag('home'),
    isSections: stateFlag('sections'),
    isItems: stateFlag('items')
  })

Guidon:

<li class="home" {{bindAttr class="isHome:active"}}>
</li>
<li class="sections" {{bindAttr class="isSections:active"}}>
</li>
<li class="items" {{bindAttr class="isItems:active"}}>
</li>

Mise à jour: la solution de Pangratz est plus jolie

1
zaplitny

Voici une solution de travail complète:

Vue:

App.NavView = Ember.View.extend({
  tagName: 'li',
  classNameBindings: ['active'],

  active: function() {
    return this.get('childViews.firstObject.active');
  }.property()
});

Modèle:

<ul>
  {{#each item in controller}}
  {{#view App.NavView}}
  {{#linkTo "item" item tagName="li"}}
      <a {{bindAttr href="view.href"}}>
        {{ item.name }}
      </a>
  {{/linkTo}}
  {{/view}}
  {{/each}}
</ul>
1
Terry

À partir de la version 0.8.0 ember-bootstrap , prend en charge les navs, y compris la gestion correcte de l'état actif. Et cela sans aucun type de hacks link-to/tagName:

{{#bs-nav type="pills"}}
   {{#bs-nav-item}}
      {{#link-to "foo"}}Foo{{/link-to}}
   {{/bs-nav-item}}
   {{#bs-nav-item}}
     {{#link-to "bar"}}Bar{{/link-to}}
   {{/bs-nav-item}}
 {{/bs-nav}}

Voir http://kaliber5.github.io/ember-bootstrap/api/classes/Components.Nav.html

0
Simon Ihmig

Un grand nombre des solutions proposées ici ne fonctionnent avec aucune version récente d'Ember (les vues étant par exemple obsolètes). De plus, le simple fait d'utiliser l'assistant link-to ne résoudra pas le problème, car bootstrap s'attend à ce que la classe active soit présente sur le <li> et non le <a>!

Je vais donc essayer de résumer les solutions qui fonctionnent réellement à partir de maintenant:

utiliser ember-cli-active-link-wrapper

L'addon fournit un composant pour ce cas d'utilisation spécial:

<ul class="nav nav-tabs">
  {{#active-link}}
    {{#link-to "foo"}}Foo{{/link-to}}
  {{/active-link}}
  {{#active-link}}
    {{#link-to "bar"}}Bar{{/link-to}}
  {{/active-link}}
</ul>

Extrait de https://stackoverflow.com/a/29939821/5556104

utilisez ember-bootstrap

ember-bootstrap fournit de nombreux composants qui intègrent la fonctionnalité d'amorçage dans votre application ember, parmi lesquels les composants de navigation:

{{#bs-nav type="tabs"}}
   {{#bs-nav-item}}
      {{#link-to "foo"}}Foo{{/link-to}}
   {{/bs-nav-item}}
   {{#bs-nav-item}}
      {{#link-to "bar"}}Bar{{/link-to}}
   {{/bs-nav-item}}
 {{/bs-nav}}

Tiré de https://stackoverflow.com/a/38279975/5556104

lien vers Hack

Un peu hacky, mais devrait fonctionner sans aucun addon supplémentaire:

<ul class="nav nav-tabs">
  {{#link-to "foo" tagName="li"}} 
    {{#link-to "foo"}}Foo{{/link-to}}
  {{/link-to}}
  {{#link-to "bar" tagName="li"}} 
    {{#link-to "bar"}}Bar{{/link-to}}
  {{/link-to}}
</ul>

Extrait de https://stackoverflow.com/a/23966652/5556104

0
Simon Ihmig

Comme d'autres personnes l'ont dit, en utilisant {{#link-to}} pour créer un lien vers une route existante, lorsque cette route est une URL actuelle, {{#link-to}} ajoutera automatiquement active à ses classes CSS.

Voir Ember numéro 4387

0
Alan Dong

la réponse de baijum ci-dessus est généralement correcte, mais dans les dernières versions d'Ember, le "bind-attr" est obsolète. Voici la nouvelle façon de l'écrire:

{{#link-to "dashboard" tagName="li"}}
    <a href="{{view.href}}">Dashboard</a>
{{/link-to}}

Comme vous pouvez le constater, c’est encore plus simple et fonctionne comme par magie.

0
Bill Lynch

Tôt ou tard, vous voulez changer le nom de vos états ou quoi que ce soit que vous ayez à parcourir le code ET la vue, ajouter une fonction à la transition Pour chaque route ne semble pas souhaitable. Mon approche est un peu plus programmatique et modularisée:

# Parent View-Tamplate, holding the navbar DOM elements
App.NavView = Ember.View.extend( 
  controller: App.NavArrayController
  templateName: "ember-nav"
)
# We Push NavItems into this array
App.NavArrayController = Ember.ArrayController.create(
  content: Ember.A([])
)
# NavItem has two settable properties and 
# an programmatic active state depending on the router
App.NavItem = Ember.Object.extend(
  title: ''
  goto: null    # <=this is the name of the state we want to go to!
  active: (->
    if App.router.currentState.name == @.get "goto"
      true
    else
      false
  ).property('App.router.currentState.name').cacheable()
)
# the actual NavElement which gets the class="active" if the 
# property "active" is true, plus a on-click binding to
# make the Router transition to this state
App.NavItemView = Ember.View.extend(
 tagName: "li"
  classNameBindings: ["active"]
  click: ->
    App.router.transitionTo(@get('goto'))
    false
)

nav-view.hbs (pour les navigateurs de style Twitter-bootstrap)

<div class="nav-collapse collapse">
  <ul class="nav">
    {{#each App.NavArrayController}}
      {{#view App.NavItemView classBinding="active" gotoBinding="goto"}}
        <a href="#" {{bindAttr data-goto="goto"}}> {{title}}</a>
      {{/view}}
    {{/each}}
  </ul>
</div>

Ainsi, je peux créer et modifier mes itinéraires dans le routeur, .__ et conserver les définitions de navigation côte à côte:

# put this somewhere close to the Router 
App.NavArrayController.pushObjects(
  [
    App.NavItem.create(
      title: 'Home'
      goto: 'home'
    ),
    App.NavItem.create(
      title: 'Chat'
      goto: 'chat'
    ),
    App.NavItem.create(
      title: 'Test'
      goto: 'test'
    )
  ]
)
0
Thomas