Question

Durandal binds view model to view before it has attached, and when you try to check element sizes using jquery it always returns 0. That's because jQuery can't get correct sizes of element which is invisible or is in invisible container.

My binding handler, which limits text with some number of lines and replaces remaining text with ellipsis, is not working when durandal is binding page, but works after second updates, when element is visible

ko.bindingHandlers.ellipsis = {
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        ko.bindingHandlers.text.update(element, valueAccessor);
        var lines = allBindings.get('lines');

        var $element = $(element);
        var lineHeight = 1.3;
        var heigth = lines * (+$element.css('font-size').substr(0, 2)) * lineHeight;

        while ($element.outerHeight() > heigth) {
            $element.text(replaceLast);
        }

        function replaceLast(index, text) {
            return text.replace(/\W*\s(\S)*$/, '...');
        }
    }
};

I had this problem also when I used jQuery.customSelect through binding handler and when I used it through binding callback manually

Was it helpful?

Solution

Use a Delayed Binding Handler. From the Durandal docs,

Sometimes your binding handler needs to work with an element only after it is attached to the DOM and when the entire composition of the view is complete. An example of this is any code that needs to measure the size of an HTML element. Durandal provides a way to register a knockout binding handler so that it does not execute until the composition is complete. To do this, use composition.addBindingHandler. One common use is in focusing elements. If you have an existing registered binding handler, you can change its execution time simply by doing this:

So your bidning handler would become the following:

composition.addBindingHandler('ellipsis', {
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        ko.bindingHandlers.text.update(element, valueAccessor);
        var lines = allBindings.get('lines');

        var $element = $(element);
        var lineHeight = 1.3;
        var heigth = lines * (+$element.css('font-size').substr(0, 2)) * lineHeight;

        while ($element.outerHeight() > heigth) {
            $element.text(replaceLast);
        }

        function replaceLast(index, text) {
            return text.replace(/\W*\s(\S)*$/, '...');
        }
    }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top