Traveling Tech Guy
Traveling Tech Guy

Reputation: 27809

Creating Bootstrap tabs using Knockout.js foreach

I'm trying to create some tabs, one per profile the user chooses to save. Each profile is a ViewModel. So I thought I'd just create another ViewModel that contains an observableArray of objects of type: {name: profile_name, model: model_converted_to_json}.

I followed this example to create my code - but I get nothing bound, for some reason.

Here's my code:
-ViewModel (I use Requirejs, that explains the external wrapper):

"use strict";
// profiles viewmodel class
define(["knockout"], function(ko) {
    return function() {
        var self = this;
        this.profilesArray = ko.observableArray();
        this.selected = ko.observable();
        this.addProfile = function(profile) {
            var found = -1;
            for(var i = 0; i < self.profilesArray().length; i++) {
                if(self.profilesArray()[i].name == profile.name) {
                    self.profilesArray()[i].model = profile.model; 
                    found = i;
                }
            }
            if(found == -1) {
                self.profilesArray().push(profile);
            }
        };
    };
}); 

-The JS code (excerpt of larger file):

var profiles = new profilesViewMode();
ko.applyBindings(profiles, $("#profileTabs")[0]); 
$("#keepProfile").on("click", function() {
    var profile = {
        name: $("#firstName").text(),
        model: ko.toJSON(model)
    };
    profiles.addProfile(profile);
    profiles.selected(profile);
    console.log(profile);
    $("#profileTabs").show();
});

-The HTML (Thanks Sara for correcting my HTML markup)

<section id="profileTabs">
    <div>
        <ul class="nav nav-tabs" data-bind="foreach: profilesArray">
            <li data-bind="css: { active: $root.selected() === $data }">
                <a href="#" data-bind="{ text: name, click: $root.selected }"></a>
            </li>
        </ul>
    </div>
</section>

I have verified that the observableArray does get new, correct value on button click - it just doesn't get rendered. I hope it's a small thing that I'm missing in my Knockout data-bind syntax.

Thanks for your time!

Upvotes: 2

Views: 4860

Answers (2)

Kato
Kato

Reputation: 40582

You are setting name using name: $('#firstName').text(); you may need to change that to .val() if this is referencing an input field (which I assumed here).

You are using .push() on the underlying array which bypasses ko's subscribers (the binding in this case)

Here is a working jsfiddle based on your code. I took some liberties with model since that wasn't included.

Upvotes: 3

RP Niemeyer
RP Niemeyer

Reputation: 114792

You will want to call push directly on the observableArray, which will both push to the underlying array and notify any subscribers. So:

self.profilesArray.push(profile);

Upvotes: 5

Related Questions