htmlcssangularjsangular-ui-tabset

How can I separate tabs headings from their bodies with angularjs?


In an angularjs project, I am using the uib-tabset directive in order to display tabs. I would like to display a left panel that is common to all tabs. So I have to add a div before or after the uib-tabset directive.

By default, the headings part is directly on top of tabs body. enter image description here

In the generated structure, I would like to include the panel inside the tabs (visually) : same side panel for all tabs

With uib-tabsets, the generated structure is like this:

<panel>
<tabs-headings>
<tabs-bodies>

With this structure, the only way I have found is to edit the css and play with position properties (left/top) in order to move the headings on top of the side panel, but I find this risky. Another way would be to duplicate the panel code inside of each tab, but I find this bad too.

Instead I would like to generate this so it would be easier to create the css :

<tabs-heading>
<panel>
<tabs-bodies>

Is there an easy way to achieve that behavior?

Thanks


Solution

  • Edit: Lol. Just saw that I'm 10 months late.

    I just ran into what you're talking about. If you are dynamically rendering content in each tab using ng-repeat, this would avoid having to remake the side panel a bunch of times.

      <div class="tabWrapper">
        <uib-tabset>
        <uib-tab index="$index + 1" ng-repeat="tab in tabs" heading="{{tab.title}}" disable="tab.disabled">
    
          <div class="sidePanel">{{tab.sidepanel}}</div> 
          <div class="tabContent">{{tab.content}}</div>
    
        </uib-tab>
        </uib-tabset>
      </div>
    

    You wouldn't need to mess with absolute positioning either:

    .sidePanel {
      float: left;
      width: 20%;
      height: 10em;
      border: 1px solid black;
      border-top: none;
    }
    

    OR, if you're using angular-ui-router, you could accomplish the static side panel by using abstract states.

    config.js

      $stateProvider
        .state('root.tabs', {
          abstract: true,
          controller: 'TabsCtrl as vm',
          templateUrl: 'templates/app-layout/tabs.tpl.html'
        })   
        .state('root.tabs.view', {
          url: '/tabsview',
          templateUrl: 'templates/app-layout/sidepanel.tpl.html'
        });
    

    tabs.tpl.html

       <div>
          <uib-tabset>
            <uib-tab index="$index + 1" ng-repeat="tab in tabs" heading="{{tab.title}}" disable="tab.disabled">
    
            <div class="sidePanelContainer" ui-view></div>
    
            <div class="tabContent">{{tab.content}}</div>
            </uib-tab>
          </uib-tabset>
        </div>
    

    sidepanel.tpl.html

    <div class="sidePanel">
      <input type="text" value="1234">
      <input type="text" value="4321">
    </div>
    

    See also: what is the purpose of use abstract state?

    Hope this helps