Wednesday, March 14, 2012

Custom Knockout binding for truncating text with an ellipsis

[UPDATE] Added an AMD version at the end. Adapting this JsFiddle I created a custom knockout binding for truncating multi-line text to fit within an available space:


ko.bindingHandlers.truncate = {
        update: function (element, valueAccessor, allBindingsAccessor, context) {
            var value = valueAccessor();
            var $element = $(element);
            var divh = $element.parent().height();
            $element.text(value());
            while ($element.outerHeight() > divh) {
                $element.text(function (index, text) {
                    return text.replace(/\W*\s(\S)*$/, '...');
                });
            }
        }
    };


Both the parent and child need to be block level elements and the parent needs a fixed height I believe.

Of course, if you have just a single line, you can do this easily with pure css (from Twitter Bootstrap)


// Text overflow
// -------------------------
// Requires inline-block or block for proper styling
.text-overflow {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Here is a JsFiddle showing this in action. [UPDATE] And now here is an AMD version. Where 'jquery' is, of course, jQuery, and 'ko' is knockout.

define(['jquery', 'ko'], function ($, ko) {
   ko.bindingHandlers.truncate = {
       update: function (element, valueAccessor) {
           var value = valueAccessor();
           var $element = $(element);
           var divh = $element.parent().height();
           $element.text(value());
           while ($element.outerHeight() > divh) {
               $element.text(function (index, text) {
                   return text.replace(/\W*\s(\S)*$/, '...');
               });
           }
       }
   };
});
    

2 comments:

  1. This is great. Thanks for this. I had to change $element.text(value()); to $element.text(value); for my use-case.

    Also if your container is a variable width and changes with window size, you can wrap the while() statement in a $(window).resize() function.

    ReplyDelete
  2. Thanks! This broke for me a couple of KO versions ago so I'll give your changes a go, see if it fixes things for me as well.

    ReplyDelete