Emberjs - как пометить активный элемент меню с помощью инфраструктуры маршрутизатора

Я пытаюсь создать вкладки навигации (взятые из 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>

Активная вкладка отмечена class="active".

Существует отличный пример статической навигационной панели и функции Router/Outlet в http://jsfiddle.net/schawaska/pfbva/, но Я не могу понять, как создать динамическое представление навигации/меню/вкладки.

Насколько я понимаю, в каждом пункте меню можно использовать привязки классов:

 classNameBindings: ['isActive:active']

Но где подходящее место для переключения атрибутов isActive?

Ответ 1

Если вы используете Ember >= 1.11, то fooobar.com/questions/108327/... ниже - правильный ответ.


Я бы создал NavigationView, см. http://jsfiddle.net/pangratz666/z8ssG/:

Рули

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

И внутри вашего маршрута connectOutlets вам нужно установить текущий элемент навигации с помощью router.set('navigationController.selected', 'home');...


Также рассмотрите репозиторий ember-bootstrap, который обертывает эту и другие функции Bootstrap внутри Ember.js

Ответ 2

Эмбер 1.11 +:

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

1.11 (bind-attr требуется):

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

Ответ 3

Некоторые из приведенных выше предложений по-прежнему действительны для случая бутстрапа twitter. Вы также можете попробовать что-то вроде этого

{{#link-to 'dashboard' tagName='li'}} 
  {{#link-to 'dashboard'}}Link Title{{/link-to}}
{{/link-to}}
  • link-to с тегом li tagName применяет активный класс к li
  • Внутренний link-to будет элементом anchor, который дает вам Open in New Tab функциональность при нажатии правой кнопки мыши

Ответ 4

Недавно появилась возможность добавления Ember-cli для этого. Он называется ember-cli-active-link-wrapper.

Установить: ember install ember-cli-active-link-wrapper

Вы можете использовать его следующим образом:

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

что приводит к:

<li class='active'>
    <a href="/" class='active'>Index</a>
</li>

Ответ 5

Я знаю, что это старый пост, но здесь есть обновления для Ember 2.4.0

Для создания ссылок вы можете написать

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

или

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

Ember автоматически устанавливает класс в активный, если текущий маршрут совпадает с маршрутом ссылки (в этом примере photoGallery).

Если вы хотите также контролировать класс "active" на других маршрутах, вы можете сделать это, установив атрибут current-when.

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

Эта ссылка будет иметь класс active на маршрутах photoGallery и photoPreview.

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

Ответ 6

Рули

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

Javascript

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

Он автоматически добавит активный класс по маршруту. Примечание. Он протестирован с использованием ember-1.0.0-pre.4.js

Ответ 7

Вы также можете изменить метод isActive на что-то вроде этого:

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

или

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

Ответ 8

Я вижу, что этот вопрос довольно старый, но если вы обновили Ember.js до RC3, вы можете использовать свойство tagName, например:

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

Вот API - http://emberjs.com/api/classes/Ember.LinkView.html

Ответ 9

Не уверен, что это очень динамично, но попытайтесь увидеть решение на http://codebrief.com/2012/07/anatomy-of-an-ember-dot-js-app-part-i-redux-routing-and-outlets/ Основная идея - проверить состояние вашего приложения.

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

Рули:

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

Update: Решение pangratz выглядит красивее

Ответ 10

Здесь полное рабочее решение:

Вид:

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

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

Шаблон:

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

Ответ 11

Рано или поздно вы хотите изменить именование своих состояний или что-то еще, что вам нужно пройти через код И представление, а также добавление функции перехода к каждому маршруту кажется нежелательным. Мой подход немного более программный и модульный:

# 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(для навигационных устройств типа 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>

Таким образом, я могу просто создавать и путать с моими маршрутами в маршрутизаторе, и сохраняйте Nav-Definitions бок о бок:

# 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'
    )
  ]
)

Ответ 12

Ответ baijum выше в основном правилен, однако в последних версиях Ember "bind-attr" устарел. Вот новый способ записи:

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

Как вы можете видеть, это еще проще и вроде работает как магия.

Ответ 13

Начиная с v0.8.0 ember-bootstrap поддерживает navs, включая правильное управление активным состоянием. И это без каких-либо привязок к /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}}

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

Ответ 14

Многие предлагаемые решения здесь не работают ни для какой новой версии Ember (например, устаревшие представления). Более того, использование помощника link-to не решит проблему, так как bootstrap ожидает, что класс active будет присутствовать на <li> не <a>!

Поэтому я попытаюсь обобщить решения, которые на самом деле работают на данный момент:

использовать ember-cli-active-link-wrapper

Аддон предоставляет компонент для этого специального использования:

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

Взято из fooobar.com/questions/108327/...

использовать ember-bootstrap

ember-bootstrap предоставляет множество компонентов, которые объединяют функциональные возможности бутстрапа в ваше приложение ember, среди которых навигационные компоненты:

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

Взято из fooobar.com/questions/108327/...

ссылка на Hack

Немного взломанный, но должен работать без дополнительного аддона:

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

Взято из fooobar.com/questions/108327/...

Ответ 15

Как и другие люди, используя {{#link-to}} для связи с существующим route, когда этот маршрут является текущим URL, {{#link-to}} автоматически добавит active в его классы CSS.

Смотрите Ember issue 4387