ui-scroll for long text virtualising

471 Views Asked by At

What is the best way of showing a very long text (in MBs) using ui-scroll ? The text is available in the form of an array but needs to be displayed as a long text document just like a textarea. I'm using ui-scroll as each word in the text is a clickable anchor tag.

Is ui-scroll-td to display each word as a column and lines as row the only way ?

More Information

  1. I have a large array containing > 2000 elements (words) which can be changed by user dynamically (both the number of elements and the element itself).
  2. I need to display these elements as a single document where each element (word) is a hyperlink which when clicked performs certain action.

  3. I need it to look like a simple scrollable div which has these words displayed as long free flowing clickable text.

  4. I was using $compile earlier to create html dynamically but the initial compile time and the compile upon element change is very significant (seconds) as I have to compile/render the whole list of elements every single time.

    1. So I thought of using ui-scroll to display which virtualizes and renders only the displayed content.

    2. But ui-scroll always display each element in a separate line like a row which is not the desired behavior for my use case.

Input:
    myList = ["Hello", "World", "This", "is", "my", "first", "dream"].

 desired Output (each word in same line with auto wrap just like a div):

 <div>
     <span ng-repeat="w in myList">
         <a ng-click="someAction()">myList[$index]</a>
         &nbsp; 
     </span>
  </div>

  Hello World This is my first dream

ui-scroll:
    <div>
       <span ui-scroll="at in info">
          <a id="at-{{$index}}" ng-click="someAction($index, $event)">
             myList[$index]}}
          </a>
          &nbsp;
       </span>
      </div>


  ui-scroll output (each word in separate line):
  Hello
   World
   This
   is
   my
   first
   dream

Kindly note that each word above is a clickable anchor. Thanks.

1

There are 1 best solutions below

0
On

Unfortunately, this is completely impossible with the angular-ui-scroll as it does not support inline/floating elements. There were some attempts to implement this feature in 2015, but now it seems frozen forever.


Infinite approach

The case you are developing is very interesting. As a possible workaround I would advise to try "infinite" approach instead of "virtualizing" one. Infinite scroll could be implemented with no additional libraries, the idea could be broken into following steps:

  • add N words into the viewport initially
  • if viewport's scrollHeight === clientHeight, add N more words; make a loop until the scrollbar appears
  • listen for viewport's scrollTop changing, invoke following when scroll happens
  • if scrollTop + clientHeight === scrollHeight add N more words; also in a loop until the height of the viewport (scrollHeight) increases or until words are over

This should drastically reduce the cost of the initial render, but since the elements out of the view are not being destroyed, the overall performance will decrease per each new elements injection.


Virtualization

After the "infinite" approach is implemented, I think you may try to turn this particular infinite scroll case into virtual one. Let's think what might be required. First, you'll need two additional elements, say, top and bottom padding elements, which will emulate virtual words. Then you will need to extend the last step of the "infinite" approach by following:

  • look into the opposite direction and find the first element that is visible in the viewport; this could be done in multiple ways (here and hundreds of other links)
  • remember scrollHeight, clip off all the elements before the found one, set the height of the top padding element into remembered value to make the the result scrollHeight the same as before clipping
  • depends on the environment/requirements you also might need to correct scroll position as it might jump up during clipping; I would like not to discuss back-jumping here, just be happy with the default overflow-anchor behaviour (though you'll have to forget about Edge and other sad guys)
  • the condition scrollTop + clientHeight === scrollHeight in our handler (say, "if we are at the very bottom") should be reconsidered as we may have non-zero bottom padding element; so it should be like "if we are at the very bottom OR if the bottom padding element becomes visible"
  • if the condition above is fulfilled, you need to add N words again and again until the bottom padding becomes invisible again, and each injection should be accomplished with decreasing of the bottom padding element's height by the value the viewport's scrollHeight is increased with; and only the edge case when "we are at the very bottom" will cause the irrevocable increasing of the viewport's scrollHeight

This way we will properly cover downward scrolling. You obviously will need to take into account upward scrolling and run the similar procedure when "the top padding becomes visible OR we are at the very top". Also the "we are at very top/bottom" and "element becomes visible" conditions could be extended with some UX-friendly deltas, say, "we are almost at..." and "the element is almost visible".

I don't think this plan covers or should cover all possible edge cases and requirements, it's just an idea how this could be done from scratch, and my guess is it's the only way you have, I mean the complete implementation by yourself. I would be happy if I'm wrong and would love to look at someone's ready-made solution.