Search code examples
jqueryjquery-uiknockout.jsknockout-mvc

Knockoutjs dynamic templating and applying jquery effects to visibility transition


Im using knockout js dynamic templating successfully to display different views depending on whether the user has clicked to view further details of an item.

basic code included below :

<div data-bind="template : {name: GetView , foreach: DisplayableItems}"></div>
<script type="text/html" id="SimpleView">
<div class="entry list">
    <h1>Simple View </h1>
    <a  data-bind="click:ToggleDisplayMode">Expand</a>
</div>
</script>
<script type="text/html" id="DetailView">
<div class="entry list">
    <h1>Detail View </h1>
    <a  data-bind="click:ToggleDisplayMode">Collapse</a>
</div>
</script>

ViewModel = function () {
var self = this ;

self.ToggleDisplayMode = function() {

    self.DisplayMode() == 'simple' ? self.DisplayMode('detail') : self.DisplayMode('simple');
};

self.GetView = function (contentItem) {

    if (contentItem.DisplayMode() == "simple")
        return "SimpleView";
    else
        return "DetailView";
 };
}

ContentItem = function() {
var self = this;

self.DisplayMode =  ko.observable("simple"); 
}

This works very nicely and toggles between showing the different views based on whether someone wants to see the simple or detailed view.

What I would like to do is apply some transitioning effects so that the detail views slides down etc using the jqueryui effects library.

Im wondering how/whether this would be possible to intercept how the visibility switch so that I could apply some effects to this.


Solution

  • One option is to use the afterRender callback of the template binding as described here.

    I actually generally prefer using a custom binding for this type of thing. Docs on custom bindings are here and a post that I have that shows some common examples here.

    In your case, the custom binding could be as simple as:

    ko.bindingHandlers.slideVisible = {
      init: function(element, valueAccessor) {
          var duration = ko.utils.unwrapObservable(valueAccessor());
          $(element).hide().slideDown(duration); 
      }
    };
    

    The init function only runs when the element is first bound and in your case when the template changes the elements are rendered again. This would just immediately hide the element and then slide it down.

    Sample here: http://jsfiddle.net/rniemeyer/mEAJR/