New collection-repeat - variable height elements


#1

Hey guys,

So the new collection repeat allows not to give any height / width, but on the other side it assumes that every element is the exact same height.

So, if I want to display some random text in my elements, I still need to give a item-height value. The problem is, I have not found not here nor elsewhere a good solution to calculate heights before rendering the items.

Any idea ?


#2

It’s not perfect but I use this:

function crHigh(str) {
  var ret= 74;
  var s= window.innerWidth/5 - 5;
  var len= str.length + 5;
  if ( len >= s ) ret= 98;
  return ret+'px';
}

I’ve wrote it with try and check with elements that I need to display.


#3

Thanks for the tip, but it’s really too much random for me… Tried it in many cases and sometimes it works, but often it doesn’t.

Still up for an answer on this !


#4

I think I got something working for me now - if anyone is interested, here is how I did it - I would gladly hear some criticism as well since I’m not sure about the efficiency of the method :

Prior to the dom display, I’m rendering an invisible element with the same classes as the future element that will hold the text block. If the said element is inside a responsive row, I’m handling this case as well by creating a parent and a previous child element. Then I return the found height and use it for item-height value. Like this :

<div collection-repeat="message in messages" item-height="getMsgHeight(message.text)">

Controller :

$scope.getMsgHeight = function (text) {
    return baseFact.getTextItemHeight(text, true, 'regularMessageBlock col', 'col col-20') + 70;
};

And the factory :

getTextItemHeight: function (text, hasPadding, myclasses, preChildClasses) {
    var element = document.createElement('div');

    var classes = myclasses.split(" ");
    for( var i = 0; i < classes.length; i++ )
        element.classList.add(classes[i]);

    if(preChildClasses) {
        var parentElement = document.createElement('div');
        parentElement.classList.add('row');

        var preChildElement = document.createElement('div');

        var preclasses = preChildClasses.split(" ");
        for( var j = 0; j < preclasses.length; j++ )
            preChildElement.classList.add(preclasses[j]);

        parentElement.appendChild(preChildElement);
        parentElement.appendChild(element);

        if(hasPadding)
            parentElement.style.width = ($localStorage.deviceData.width - 38) + "px"; // device width stored before

        parentElement.style.visibility = "hidden";
        document.body.appendChild(parentElement);
    }
    else {
        if(hasPadding)
            element.style.width = ($localStorage.deviceData.width - 38) + "px"; // device width stored before

        element.style.visibility = "hidden";
        document.body.appendChild(element);
    }

    element.appendChild(document.createTextNode(text));
    var $height = element.clientHeight;
    element.remove();
    return $height;
}

I would very much appreciate a feedback on this.

Thanks !


#5

For information, I dropped that solution for performances issues - as expected, it can’t perform really well and the loading time is really too much hurt. I recommend dropping collection-repeat as well for now, it’s simply not production ready, and stick to ng-repeat with infinite scrolling, it’s a lot better.


#6

what about precalculating the sizes instead of doing it in the template?.
And instead of creating everytime a new element and a new parrent and so on reuse them or create then by default and use them in that function --> clear css classess and only readd classes :wink:


#7

That’s a good point, actually. But precalculating has its limit - you need to have the data fetched already, which means you can precalculate in the resolve function of the state, or in the controller, which would still induce performance issues.

Keeping the element and reusing it is completely valid, though, and should have been the path I’d have followed :blush: