Как связать активный класс ссылки с помощью нового маршрутизатора Ember?
Я использую Twitter Bootstrap для навигации в своем приложении Ember.js. Bootstrap использует класс active
в теге li
, который обертывает ссылки навигации, а не устанавливает класс active
в самой ссылке.
Ember.js new linkTo
helper установит класс active
в ссылке, но (насколько я вижу) не предлагает привязываться к этому свойству.
Сейчас я использую этот уродливый подход:
{{#linkTo "inbox" tagName="li"}}
<a {{bindAttr href="view.href"}}>Inbox</a>
{{/linkTo}}
Это выведет:
<li class="active" href="/inbox"><a href="/inbox">Inbox</a></li>
Это то, что я хочу, но недействительный HTML.
Я также попытался привязать к сгенерированному свойству LinkView active
из родительского представления, но если вы это сделаете, родительское представление будет отображаться дважды, прежде чем оно будет вставлено, что приведет к ошибке.
Помимо ручного воссоздания логики, используемой внутренне помощником linkTo
для назначения класса active
для ссылки, есть ли лучший способ добиться этого эффекта?
Ответы
Ответ 1
Вы также можете использовать вложенные ссылки:
{{#link-to "ccprPracticeSession.info" controller.controllers.ccprPatient.content content tagName='li' href=false eventName='dummy'}}
{{#link-to "ccprPracticeSession.info" controller.controllers.ccprPatient.content content}}Info{{/link-to}}
{{/link-to}}
Ответ 2
Нам определенно нужно более публичное, постоянное решение, но что-то вроде этого должно работать пока.
Шаблон:
<ul>
{{#view App.NavView}}
{{#linkTo "about"}}About{{/linkTo}}
{{/view}}
{{#view App.NavView}}
{{#linkTo "contacts"}}Contacts{{/linkTo}}
{{/view}}
</ul>
Определение вида:
App.NavView = Ember.View.extend({
tagName: 'li',
classNameBindings: ['active'],
active: function() {
return this.get('childViews.firstObject.active');
}.property()
});
Это зависит от нескольких ограничений:
Я предоставил живой JSBin этой работы.
Ответ 3
Хорошо, я взял отличную идею @alexspeller и преобразовал ее в ember-cli:
приложение/компоненты/ссылка-li.js
export default Em.Component.extend({
tagName: 'li',
classNameBindings: ['active'],
active: function() {
return this.get('childViews').anyBy('active');
}.property('[email protected]')
});
В моем навигаторе я:
{{#link-li}}
{{#link-to "squares.index"}}Squares{{/link-to}}
{{/link-li}}
{{#link-li}}
{{#link-to "games.index"}}Games{{/link-to}}
{{/link-li}}
{{#link-li}}
{{#link-to "about"}}About{{/link-to}}
{{/link-li}}
Ответ 4
На основе ответа katz вы можете переопределить свойство active
при нажатии на элемент nav parentView
.
App.NavView = Em.View.extend({
tagName: 'li',
classNameBindings: 'active'.w(),
didInsertElement: function () {
this._super();
var _this = this;
this.get('parentView').on('click', function () {
_this.notifyPropertyChange('active');
});
},
active: function () {
return this.get('childViews.firstObject.active');
}.property()
});
Ответ 5
Я только что написал компонент, чтобы сделать это немного приятнее:
App.LinkLiComponent = Em.Component.extend({
tagName: 'li',
classNameBindings: ['active'],
active: function() {
return this.get('childViews').anyBy('active');
}.property('[email protected]')
});
Em.Handlebars.helper('link-li', App.LinkLiComponent);
Использование:
{{#link-li}}
{{#link-to "someRoute"}}Click Me{{/link-to}}
{{/link-li}}
Ответ 6
Я воссоздал логику, используемую внутренне. Другие методы казались более хаки. Это также облегчит повторное использование логики в других местах, где мне может не понадобиться маршрутизация.
Используется как это.
{{#view App.LinkView route="app.route" content="item"}}{{item.name}}{{/view}}
App.LinkView = Ember.View.extend({
tagName: 'li',
classNameBindings: ['active'],
active: Ember.computed(function() {
var router = this.get('router'),
route = this.get('route'),
model = this.get('content');
params = [route];
if(model){
params.push(model);
}
return router.isActive.apply(router, params);
}).property('router.url'),
router: Ember.computed(function() {
return this.get('controller').container.lookup('router:main');
}),
click: function(){
var router = this.get('router'),
route = this.get('route'),
model = this.get('content');
params = [route];
if(model){
params.push(model);
}
router.transitionTo.apply(router,params);
}
});
Ответ 7
Вы можете пропустить расширение представления и использовать следующее.
{{#linkTo "index" tagName="li"}}<a>Homes</a>{{/linkTo}}
Даже без href Ember.JS все равно будет знать, как подключиться к элементам LI.
Ответ 8
Для этой же проблемы я пришел с решением на основе jQuery, не уверенным в производительности, но он работает из коробки. Я снова открываю Ember.LinkView и расширил его.
Ember.LinkView.reopen({
didInsertElement: function(){
var el = this.$();
if(el.hasClass('active')){
el.parent().addClass('active');
}
el.click(function(e){
el.parent().addClass('active').siblings().removeClass('active');
});
}
});
Ответ 9
Текущие ответы на момент написания датированы. В более поздних версиях Ember, если вы используете {{link-to}}
, он автоматически устанавливает класс 'active'
в элементе <a>
, когда текущий маршрут соответствует целевой ссылке.
Так что просто напишите свой css с ожиданием, что <a>
будет иметь active
, и он должен сделать это из коробки.
К счастью эта функция добавлена. Весь материал, который был необходим для решения этой "проблемы" ранее, довольно нелепо.