emberjs - cómo marcar elemento de menú activo usando la infraestructura del router


Estoy tratando de crear pestañas de navegación (tomadas 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>

La pestaña activa está marcada con class="active".

Hay un gran ejemplo de la barra de navegación estática y la función Router/Outlet en http://jsfiddle.net/schawaska/pfbva / , pero No puedo entender cómo crear una vista dinámica de barra de navegación / menú / pestaña.

Por lo que entiendo, es posible usar enlaces de clase en cada elemento del menú:

 classNameBindings: ['isActive:active']

Pero ¿dónde está el lugar correcto para cambiar isActive atributos ?

Author: James A. Rosen, 2012-07-24

15 answers

Si estás usando Ember > = 1.11, entonces https://stackoverflow.com/a/14501021/65542 abajo está la respuesta correcta.


Crearía un NavigationView, véase http://jsfiddle.net/pangratz666/z8ssG/:

Manillar:

<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()
    })
});

Y dentro de su ruta connectOutlets tiene que configurar el elemento de navegación actual a través de router.set('navigationController.selected', 'home');...


También eche un vistazo al repositorio ember-bootstrap, que envuelve esto y más características de Bootstrap inside Ember.js

 26
Author: pangratz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:12

Ember 1.11+:

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

Ember bind-attr requerido):

{{#link-to "dashboard" tagName="li"}}
  <a {{bind-attr href="view.href"}}>Dashboard</a>
{{/link-to}}
 154
Author: lesyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-24 16:50:59

Algunas de las sugerencias anteriores siguen siendo válidas para el caso bootstrap de twitter. También puedes probar algo como esto

{{#link-to 'dashboard' tagName='li'}} 
  {{#link-to 'dashboard'}}Link Title{{/link-to}}
{{/link-to}}
  1. El link-to con li tagName aplica la clase activa al li
  2. El interior link-to sería un elemento anchor que le da Open in New Tab funcionalidad cuando se hace clic con el botón derecho
 17
Author: selvagsz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-08 14:30:05

Recientemente un complemento Ember-cli vino disponible para hacer esto. Se llama ember-cli-active-link-wrapper.

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

Puedes usarlo así:

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

Que resulta en:

<li class='active'>
    <a href="/" class='active'>Index</a>
</li>
 10
Author: Willem de Wit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-25 07:38:05

Sé que este es un post antiguo, pero aquí hay actualizaciones para Ember 2.4.0

Para crear enlaces puede escribir

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

O

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

Ember establecerá automáticamente la clase como activa cuando la ruta actual coincida con la ruta del enlace (en este ejemplo photoGallery).

Si también desea controlar la clase 'active' en otras rutas, puede hacerlo configurando el atributo current-when.

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

Este enlace tendrá active clase en ambos photoGallery y photoPreview ruta.

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

 7
Author: Ivan Bajalovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-02 10:41:01

Manillares

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

Javascript

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

Agregará la clase activa automáticamente en función de la ruta. Nota: Se prueba usando ember-1.0.0-pre.4.js

 4
Author: ketan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-16 12:51:09

También puedes cambiar el método isActive a algo como esto:

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

O

isActive: function() {
    return this.get('controller.target.currentState.path') === "root.firms";
}.property("controller.target.currentState"),
 3
Author: pjlammertyn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-20 11:29:39

Veo que esta pregunta es bastante antigua, pero si actualizas Ember.js al RC3 puedes usar la propiedad tagName, como:

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

Aquí está la API - http://emberjs.com/api/classes/Ember.LinkView.html

 3
Author: Wojciech Bednarski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-03 01:21:41

No estoy seguro de si es muy dinámico, pero trate de ver la solución en http://codebrief.com/2012/07/anatomy-of-an-ember-dot-js-app-part-i-redux-routing-and-outlets/ La idea principal es comprobar el estado de su aplicación

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')
  })

Manillar:

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

Actualización: la solución de pangratz se ve más bonita

 1
Author: zaplitny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-24 11:43:18

Aquí hay una solución de trabajo completa:

Vista:

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

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

Plantilla:

<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
Author: Terry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-14 21:20:04

Tarde o temprano desea cambiar el nombre de sus estados o lo que sea que tenga que pasar por el código Y la vista también, también agregar una función a la transiciónpara cada ruta no parece deseable. Mi enfoque es un poco más programático y modularizado:

# 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 (para twitter-bootstrap-estilo navs)

<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>

De esta manera, puedo crear y jugar con mis rutas en el enrutador, y mantener las definiciones de Navegación lado a lado:

# 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
Author: Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-27 19:18:04

La respuesta de Baijum anterior es mayormente correcta, sin embargo en las últimas versiones de Ember el "bind-attr" está en desuso. Aquí está la nueva forma de escribirlo:

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

Como puedes ver, es aún más fácil y funciona como magia..

 0
Author: Bill Lynch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-21 16:35:03

Comenzando con v0.8.0 ember-bootstrap soporta navs, incluyendo el manejo correcto del estado activo. Y que sin ningún tipo de hacks de enlace a/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}}

Véase http://kaliber5.github.io/ember-bootstrap/api/classes/Components.Nav.html

 0
Author: Simon Ihmig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-09 08:37:32

Muchas de las soluciones propuestas aquí no funcionan para ninguna versión reciente de Ember (por ejemplo, las vistas están obsoletas). Además, solo usar el ayudante link-to no resolverá el problema, ya que bootstrap espera que la clase active esté presente en el <li> no en el <a>!

Así que trataré de resumir las soluciones que de hecho funcionan a partir de ahora:

Use ember-cli-active-link-wrapper

El complemento proporciona un componente para este caso de uso especial:

<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>

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

Use ember-bootstrap

Ember-bootstrap proporciona muchos componentes que integran la funcionalidad de bootstrap en su aplicación ember, entre ellos los componentes nav:

{{#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}}

Tomado de https://stackoverflow.com/a/38279975/5556104

Enlace-para hackear

Algo hacky, pero debería funcionar sin ningún complemento adicional:

<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>

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

 0
Author: Simon Ihmig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:07

Como otras personas dijeron, usando {{#link-to}} para enlazar a un route existente, cuando esa ruta es URL actual, {{#link-to}} agregará automáticamente active a sus clases CSS.

Véase Ember issue 4387

 0
Author: Alan Dong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-31 19:55:11