Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to implement a tabpanel in ember?

Tags:

tabs

ember.js

I'm new to ember and trying to build a Ember driven web application. I've read various tuts and studies several examples. The basic concepts are clear but now I'am stuck on trying to implement a tabpanel. My approach is as follows:

View

Configurator.TabPanelView = Ember.View.extend({
    classNames: ['tabPanel'],
    templateName: 'tabPanel'
});

Template

<script type="text/x-handlebars" data-template-name='tabPanel'>
  <div class='tabHead'>
      <ul>
          {{#each tabViews}}
          <li {{action "{{this.actionName}}" target="{{this.value}}"}} >{{this.title}}</li>
          {{/each}}
      </ul>
      <div class="tab-content">{{outlet}}</div>
  </div>
</script>

Usage in App

var tab= Configurator.TabPanelView.create({

            classNames: ['assortment'],
            tabViews: [{ title: 'First', value:'Foo', actionName: 'firstTab' },{title: 'Second', value:'Foo', actionName: 'secondTab' }],

            firstTab: Ember.View.extend({
                templateName: 'first'
            }),
            secondTab: Ember.View.extend({
                templateName: 'second'
            })
        });
        tab.appendTo("body");

The TabTemplate is rendered correctly but if I try to click on the li-elements following error is thrown

Uncaught Error: assertion failed: Target <(subclass of Ember.View):ember217> does not have action {{this.actionName}}

I'm also curious if I should use a router to implement tabbing. But as far as i can see routers act on application level and are intended to be used in single UI-compos.

like image 291
Franatique Avatar asked Oct 08 '12 19:10

Franatique


2 Answers

The problem is in your template:

<li {{action "{{this.actionName}}" target="{{this.value}}"}} >{{this.title}}</li>

AFAIK, actions can't be bound, so when you write this, it tries to call the method {{this.actionName}} instead of firstTab, for example.

I think this is a typical example where you should use a Ember.CollectionView with an itemViewClass which has the click method, i.e.:

App.MyCollectionView = Ember.CollectionView.extend({
  tagName: 'ul',
  templateName: 'the-template-name',
  itemViewClass: Ember.View.extend({
    click: function() {
      var actionName = this.get('content.actionName'),
          target = this.get('controller.target');
      target.send(actionName);
    }
  })
});

The code above is surely not right, but the idea is here.

But I think the Router is the right way to do that. I suggest you to take a look at the Ember Router example by @ghempton, where it defines tab with Ember.Router.

like image 56
louiscoquio Avatar answered Nov 18 '22 02:11

louiscoquio


You have 2 options:

1) each tabpage has its own controller, view and must also be defined in the router

<script type="text/x-handlebars" data-template-name="tabs"> 
    <div> 
      <ul class="nav nav-tabs"> 
        {{#view Bootstrap.TabItem item="info"}} 
          <a {{action gotoInfo}}>Info</a> 
        {{/view}} 
        {{#view Bootstrap.TabItem item="anamnese"}} 
          <a {{action gotoAnamnese}}>Anamnese</a> 
        {{/view}} 
        {{#view Bootstrap.TabItem item="medication"}} 
          <a {{action gotoMedication}}>Medication</a>  
        {{/view}} 
      </ul> 
      {{outlet}} 
    </div> 
</script>      

Bootstrap.TabItem = Ember.View.extend({
    tagName: 'li',
    classNameBindings: ['isActive:active'],

    isActive: function() {
        return this.get('item') === this.get('controller.selectedTab');
    }.property('item', 'controller.selectedTab').cacheable()
}); 

2) all tabpages are in one large view, and tabpages will be hidden or shown

{{#view Ember.TabContainerView currentView="info"}}
  <ul class="nav nav-tabs">
    {{#view Bootstrap.TabView value="info"}}<a>Info</a>{{/view}}
    {{#view Bootstrap.TabView value="anamnese"}}<a>Anamnese</a>{{/view}}
    {{#view Bootstrap.TabView value="medication"}}<a>Medication</a>{{/view}}
  </ul>
  {{#view Ember.TabPaneView viewName="info"}}
  {{view EEPD.InfoView}}
  {{/view}}
  {{#view Ember.TabPaneView viewName="anamnese"}}
  {{view EEPD.AnamneseView}}
  {{/view}}
  {{#view Ember.TabPaneView viewName="medication"}}
  {{view EEPD.MedicationView}}
  {{/view}} 
{{/view}}

Bootstrap.TabView = Ember.TabView.extend({
    tagName: 'li',
    classNameBindings: ['isActive:active'],

    isActive: function() {
        return this.get('value') === this.get('tabsContainer.currentView');
    }.property('tabsContainer.currentView').cacheable()
});
like image 1
pjlammertyn Avatar answered Nov 18 '22 01:11

pjlammertyn