Gaui
Gaui

Reputation: 8949

Twitter Bootstrap nav tabs conflict with KnockoutJS

I'm having a problem with "Basic Tabs". I'm rendering the tabs in a View in MVC and then I have bunch of KnockoutJS code in three different Partial Views.

My problem is that Knockout is conflicting with other Knockout code because each Partial View creates a MVVM and applies bindings.

Is there some way I can skip rendering the DIV (with the Partial Views) until the relevant tab is pressed?

Here is my code for the regular View:

<ul class="nav nav-tabs" id="myTab">
    <li class="active"><a href="#attributes">Attributes</a></li>
    <li><a href="#interestgroups">Interest groups</a></li>
    <li><a href="#categories">Categories</a></li>
</ul>
<div class="tab-content">
    <div id="attributes" class="tab-pane active">
        @Html.Partial("_AttributesPartial")
    </div>
    <div id="interestgroups" class="tab-pane">
        @Html.Partial("_InterestGroupsPartial")
    </div>
    <div id="categories" class="tab-pane">
        @Html.Partial("_InterestGroupCategoriesPartial")
    </div>
</div>

<script type="text/javascript">
    $(function () {
        $('#myTab a:first').tab('show');
    });

    $('#myTab a').click(function (e) {
        e.preventDefault();
        $(this).tab('show');
    });
</script>

Upvotes: 1

Views: 1569

Answers (1)

Jon Jaques
Jon Jaques

Reputation: 4400

Something to watch out for would be calling ko.applyBindings more than once with only one argument.

For instance—if you have more than one view model on a page (I'm inferring from your question), then you need to scope it, by passing in the container element as the second argument.

Per your comment, if you want to lazy load the stuff you just have to listen for the 'shown' event.

(this is pseudocode, you'll have to fill in the details)

$('#attributes').on('shown', function (e) {
   initKOView(e.target);  // some logic to determine which viewModel to bind to.
})

function initKOView(target) {
   $(target).load('controller/_RenderPartial?path=' + target, function(data) {
      $(this).html(data);
      // Once the data comes back, apply your bindings and make sure to scope it.
      ko.applyBindings(viewModels[target], this);
   })
}

As discussed here, there is not really a way to teardown whole sets of bindings currently - so you'll still want to scope your view model.

https://github.com/SteveSanderson/knockout/issues/41#issuecomment-749171

Then in your controller, you'll want to add a PartialViewResult

public PartialViewResult _RenderPartial(string path)
{
    return PartialView(path);
}

Of course, you can have a separate controller action for each one too, and skip the parameterized loading. Also, you'll want to nix all of the @Html.Partial() stuff out of your master view too.

Upvotes: 2

Related Questions