nathan rogers
nathan rogers

Reputation: 300

knockout JS tabs, toggle active

I feel like I'm almost there, but I keep running in circles.I'm running 2 loops, one for tabs, other for tab contents. It's looping just fine, but now I need to make the correct ones either active or inactive on load.

<div id="tab">
    <ul class="nav nav-tabs" role="tablist">
        <!--ko foreach: $parent.tabArray-->         
            <li data-bind="click: toggleActive(init), css: init ? 'active': ''">
                <a data-bind="attr: {href: '#' + name}, text: name"></a>
            </li>

        <!--/ko-->
    </ul>
</div>

I've tried to use this toggleActive(init) function (init being a boolean value on the object in the array), and toggling that value. Then an inline boolean conditional to decide whether this element has the css class 'active'. This isn't functioning correctly. Any ideas?

    var tabSetUp = function () {
        ko.components.register('MainContent', {
            template: MCTemplate
        });

        var self = this;

        self.toggleActive = function (clicked) {
         if (clicked) {
            return false;
         }
        else {
            return true;
        }
      }
    }
    tabSetUp();

//example of my array
    var MainViewModel = {
        tabArray: [
                { name: 'bob', init: true },
                { name: 'bib', init: false },
                { name: 'bab', init: false },
                { name: 'bub', init: false },
                { name: 'beb', init: false },
        ]
    };

Upvotes: 1

Views: 5456

Answers (2)

Wayne Ellery
Wayne Ellery

Reputation: 7958

The easiest way is to have a observable which stores the active tab.

self.tabArray = [
    { name: 'bob'},
    { name: 'bib'},
    { name: 'bab'},
    { name: 'bub'},
    { name: 'beb'},
];

self.selectedTab = ko.observable(self.tabArray[0]);

Then when the tab is clicked use the click binding. By default the item in the loop will be based as a parameter which in this case is the tab. Then you can use the css binding to check if the active tab is equal to the tab in the loop. $data will be the tab in the loop:

<!--ko foreach: tabArray-->         
    <li data-bind="click: $parent.toggleActive, css: $parent.selectedTab() == $data ? 'active': ''">
        <a data-bind="attr: {href: '#' + name}, text: name"></a>
    </li>
<!--/ko-->

And then the toggleTab function will set the active tab:

self.toggleActive = function (tab) {
    self.selectedTab(tab);
};

JsFiddle

Upvotes: 2

Fabio
Fabio

Reputation: 11990

You have to make some changes in your code.

var MainViewModel = {
        tabArray: [
                { name: 'bob', init: true },
                { name: 'bib', init: false },
                { name: 'bab', init: false },
                { name: 'bub', init: false },
                { name: 'beb', init: false },
        ],
        toggleActive: function (clicked) {
            alert(clicked);
        }
 };

ko.applyBindings(MainViewModel);

When you want to bind a parametrised function to click you must use click: function () { yourFunction(yourParameter); }

HTML

<ul class="nav nav-tabs" role="tablist">
     <!--ko foreach: tabArray-->         
         <li data-bind="click: function() { $root.toggleActive(init) }, css: init ? 'active': ''">
             <a data-bind="attr: {href: '#' + name}, text: name"></a>
         </li>
      <!--/ko-->
 </ul>

Example working https://jsfiddle.net/qm9ukac5/

Upvotes: 0

Related Questions