2013-01-14 16 views
22

Sto utilizzando Twitter Bootstrap per la navigazione nella mia app Ember.js. Bootstrap utilizza una classe active nel tag li che avvolge i collegamenti di navigazione, anziché impostare la classe active sul collegamento stesso.Come si associa alla classe attiva di un collegamento utilizzando il nuovo router Ember?

Il nuovo helperdi Ember.js imposta una classe active sul collegamento ma (per quanto posso vedere) non offre alcun aggancio a tale proprietà.

In questo momento, sto usando questo approccio brutta:

{{#linkTo "inbox" tagName="li"}} 
    <a {{bindAttr href="view.href"}}>Inbox</a> 
{{/linkTo}} 

Questo stamperà:

<li class="active" href="/inbox"><a href="/inbox">Inbox</a></li> 

Che è quello che voglio, ma non è valido HTML.

Ho anche provato ad associare la proprietà active di LinkView generata dalla vista genitore, ma se si esegue questa operazione, la vista genitore verrà sottoposta a rendering due volte prima che venga inserita e che generi un errore.

Oltre a ricreare manualmente la logica utilizzata internamente dall'assistente linkTo per assegnare la classe active al collegamento, esiste un modo migliore per ottenere questo effetto?

+0

A causa di una modifica recente, questo non funziona nemmeno più (dato che l'helper linkTo non imposta più il contesto della vista alla sua vista). – Bastes

+2

Per chi si imbatte in questo, ho trovato queste risposte più utili: http://stackoverflow.com/questions/11628489/emberjs-how-to-mark-active-menu-item-using-router-infrastructure – woz

+1

Found una soluzione migliore [qui] (http://stackoverflow.com/questions/14412073/assigning-active-class-to-selected-list-item-in-emberjs). – Volox

risposta

8

È inoltre possibile utilizzare nidificato Link-to:

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

Si noti che sine ember v1.0.0-rc.3 l'href è impostato su false se tagName! == 'a' ([source] (https://github.com/emberjs/ember.js/pull/1849)) –

+0

Ho cambiato la risposta accettata a questo perché questo è come lo faccio ora, e ho aggiornato la risposta per rimuovere href = false –

+0

Questo non è molto più bello –

27

Abbiamo sicuramente bisogno di una soluzione pubblica più permanente, ma qualcosa del genere dovrebbe funzionare per ora.

Il modello:

<ul> 
{{#view App.NavView}} 
    {{#linkTo "about"}}About{{/linkTo}} 
{{/view}} 

{{#view App.NavView}} 
    {{#linkTo "contacts"}}Contacts{{/linkTo}} 
{{/view}} 
</ul> 

La definizione della vista:

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

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

Questo si basa su un paio di vincoli:

  • La vista nav contiene una vista singola, bambino statica
  • È possibile utilizzare una vista per il proprio <li> s. C'è un sacco di dettagli in the docs su come personalizzare l'elemento di una vista dalla sua definizione JavaScript o da Handlebars.

Ho fornito a live JSBin di questo funzionamento.

+0

C'è qualche ragione per cui questo non funzionerebbe con itemViewClass di CollectionView? Mi sembra che l'istanza di itemViewClass non abbia alcuna childview. – mcginniwa

+1

@YehudaKatz bella soluzione, ho appena trovato questo dopo aver risposto a una domanda correlata. Ho pensato di aggiungere un commento qui dato che il mio approccio potrebbe aiutare chiunque sia bloccato da uno dei vincoli che hai menzionato. Totalmente d'accordo c'è bisogno di qualcosa di più pubblico/permanente, ci penserà un po '. http://stackoverflow.com/questions/14412073/assigning-active-class-to-selected-list-item-in-emberjs/14416595#14416595 –

+5

Questo non sembra funzionare (più?) - si innesca un " hai provato a ri-renderizzare la vista dopo che era stata sottoposta a rendering ma prima che venisse inserita nel DOM "errore. La mia soluzione hack-ish funziona ancora. –

2

Ho ricreato la logica utilizzata internamente. Gli altri metodi sembravano più hackerati. Ciò renderà anche più facile riutilizzare la logica altrove, altrimenti non avrei bisogno di routing.

Utilizzato in questo modo.

{{#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); 
    } 
}); 
+2

L'ho accettato perché è probabilmente il modo migliore per farlo - le altre risposte sono state tutte interrotte con i nuovi aggiornamenti di Ember.js. Tuttavia, la cosa più semplice e più affidabile da fare nel mio caso è stata la patch di bootstrap in modo che una classe attiva sul tag 'a' abbia lo stesso effetto di una classe attiva sul' li'. –

+1

Che può essere fatto aggiungendo il seguente dopo la riga '4634' in' bootstrap.css' (versione 2.3.2): '.navbar .nav a.active, .navbar .nav a.active:hover, .navbar .nav a.active: focus' – knownasilya

+0

Questa soluzione non utilizza un tag A che rompe la solita funzionalità di collegamento nei browser – alexspeller

6

Sulla risposta Katz', si può avere la proprietà active essere ricalcolata quando si fa clic dell'elemento 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() 
}); 
+0

Questo è un buon inizio, ma quando si aggiorna la pagina, la classe attiva è sparita. –

+2

Quando si imposta anche 'this.notifyPropertyChange ('active');' in 'this._super() 'il problema con l'aggiornamento è fisso. –

0

Per lo stesso problema qui sono venuto con una soluzione a base di jQuery non è sicuro su riduzioni di prestazioni, ma si sta lavorando fuori dalla scatola. Riapre Ember.LinkView e lo estendono.

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

Si può saltare l'estensione di una vista e utilizzare il seguente.

{{#linkTo "index" tagName="li"}}<a>Homes</a>{{/linkTo}} 

Anche senza un href Ember.JS saprà comunque come agganciare agli elementi LI.

+0

Questa soluzione lascia il collegamento senza un HREF che rompe le solite interazioni del browser (tasto destro per aprire in una nuova finestra, copiare url ecc.) – alexspeller

5

ho appena scritto un componente per rendere questo un po 'più bello:

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

Usage:

{{#link-li}} 
    {{#link-to "someRoute"}}Click Me{{/link-to}} 
{{/link-li}} 
+0

potresti spiegare come funziona? Ho una domanda aperta su di esso – sunrize920

0

risposte correnti al momento della scrittura sono datati. Nelle versioni successive di Ember, se si utilizza {{link-to}}, viene automaticamente impostata la classe 'active' sull'elemento <a> quando la rotta corrente corrisponde al collegamento di destinazione.

Quindi basta scrivere il tuo css con l'aspettativa che il avrà active e dovrebbe farlo immediatamente.

Fortunato quella funzione è stata aggiunta. Tutto ciò che è stato necessario per risolvere questo "problema" è abbastanza ridicolo.

9

Beh ho preso quello che @alexspeller grande idea e convertito a Ember-cli:

app/componenti/Link-li.js

export default Em.Component.extend({ 
    tagName: 'li', 
    classNameBindings: ['active'], 
    active: function() { 
     return this.get('childViews').anyBy('active'); 
    }.property('[email protected]') 
}); 

Nella mia barra di navigazione ho:

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

Grazie mille ! Non riuscivo a capire come farlo con ember-cli – sunrize920

+2

Buona fortuna con 'childViews' nell'era Glimmer. –

Problemi correlati