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>
!
Поэтому я попытаюсь обобщить решения, которые на самом деле работают на данный момент:
Аддон предоставляет компонент для этого специального использования:
<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, среди которых навигационные компоненты:
{{#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