KnockoutJS Tabs

by Farzad Cyrus

HTML

<div id="wrapper">
    <h3>
        <p>You have selected the <strong data-bind="text: selectedSection().name"></strong></p>
        
    </h3>
    
    <div class="tab">
        <ul class="tab-nav" data-bind="foreach: sections">
            <li data-bind="css: {active: isSelected}, click: $parent.selectedSection">
                <a href="#"><span data-bind="text: name" /></a>
            </li>
        </ul>
        <div class="tab-content" data-bind="template: {name: getTemplate}">
        </div>
    </div>
    
    <p>You can select the third tab or random tab by clicking the buttons bellow.<br>The random button was clicked <strong data-bind="text: numberOfClicks"></strong> times.</p>
        
    <p>
        <button data-bind="click: selectThirdTab">Selected Third Tab</button>
        <button data-bind="click: selectRandomTab">Select Random Tab</button>
    </p>    
    
</div>
<script id="one" type="text/html">
    <div class="inner">The content of the first tab goes here</div>
</script>
<script id="two" type="text/html">
    <div class="inner">The content of the second tab goes here</div>
</script>
<script id="three" type="text/html">
    <div class="inner">The content of the third tab goes here</div>
</script>

CSS

body, html {
    font-family: Arial;
    color:#223344;
    font-size: 12px;
}
p {
    padding: 0 0 10px 0;
    margin: 10px 0 0 0;
    line-height:18px;
}
#wrapper {
    padding:20px;
}
.tab {
    width:400px;
    height:auto;
}
.tab-nav {
    list-style-type:none;
    border-bottom:1px solid #cccccc;
}
.tab-nav li {
    display:inline-block;
    width:auto;
    height:30px;
    line-height:30px;
    border:1px solid #cccccc;
    background:#eeeeee;
    padding:0 10px;
    margin-bottom:-1px;
    cursor: pointer;
    margin-right: 2px;
}
.tab-nav li a {
    text-decoration:none;
    color:#222222;
}
.tab-nav li.active {
    background:#ffffff;
    border-bottom-color:#ffffff;
}
.tab-content {
    border-width: 0 1px 1px 1px;
    border-style: solid;
    border-color:#cccccc;
    padding:20px;
}
button {
    border: 1px solid #114477;
    background: #3a5a7a;
    width: auto;
    height: 30px;
    padding: 0 10px;
    line-height:30px;
    display:inline-block;
    margin: 0 10px 0 0;
    color:#ffffff;
    cursor:pointer;
}
strong {
    font-weight: bold;
}

JavaScript

function randomIntFromInterval(min,max) {
    return Math.floor(Math.random() * (max-min + 1) + min);
}

var tab = function (name, id, selected) {
    this.name = name;
    this.id = id;
    this.isSelected = ko.computed(function () {
        return this === selected();
    }, this);
}


var ViewModel = function () {
    var self = this;
    self.selectedSection = ko.observable();
    
    self.sections = ko.observableArray([
        new tab('First Tab', 'one', self.selectedSection),
        new tab('Second Tab', 'two', self.selectedSection),
        new tab('Third Tab', 'three', self.selectedSection)
    ]);
    
    var numberOfTabs = self.sections().length,
        firstTab = 0,
        secondTab = 1,
        thirdTab = 2,
        lastTab = numberOfTabs - 1;
    
    // Inialising the Default Tab
    self.selectedSection(self.sections()[firstTab]);
    
    self.getTemplate = function (item) {
        var selected = self.selectedSection();
        return selected && selected.id;
    };
    
    // Select the Third Tab
    self.selectThirdTab = function() {
        self.selectedSection(self.sections()[thirdTab]);
    }
    
    self.numberOfClicks= ko.observable(0);
    self.incrementClickCounter = function() {
        var previousCount = this.numberOfClicks();
        this.numberOfClicks(previousCount + 1);
    }
    
    // Select Random Tab
    self.selectRandomTab = function() {
        
        if (numberOfTabs > 1) {
            // Limiting Number of Clicks to 3
            if(self.numberOfClicks() < 3) {
                self.incrementClickCounter(1);
                self.selectedSection(self.sections()[randomIntFromInterval(0, lastTab)]);
            }
            
        } else {
            alert('Sorry there isn\'t enough number of tabs!');
        }
    }
}
ko.applyBindings(new ViewModel());