shaunc / ember-grid

declarative table for ember
MIT License
15 stars 4 forks source link

Nub of rendering challenge #2

Closed shaunc closed 9 years ago

shaunc commented 9 years ago

Given

  {{#eg-body}}
    {{my-component value="name"}}
  {{/eg-body}}

We need to render

    {{my-component value="name"}}

In the context of the individual row. So:

1) look up contents of "eg-body" for given column 2) render contents in a custom wrapper component

What is relevant "contents of 'eg-body'? The dom nodes aren't sufficient. What we really want is the template (template string)? The question is, is that available?

shaunc commented 9 years ago

In my branch here I've replaced the "hidden" ember-collections with simple slices (which helps with speed)... (no longer working after merge). Thus the body rows from the definition are in order. However, the ones from ember-collection are still an unordered map. Do you have something concrete in mind by " body rows using the same technique as header rows"?

shaunc commented 9 years ago

btw -- does getting rid of run.next in "willInsertElement" actually work for you? I tried and got lots of warnings about modifying properties during render cycle. (EDIT ah -- you still have it in eg-column)

BryanCrotaz commented 9 years ago

I think it worked for header and footer but not body. I don't understand the glimmer life cycle yet.

By same as header, I mean a simple each...header-cell with inline-block positioning.

Worth speed testing?

shaunc commented 9 years ago

I'll give inline-block a whirl ... let me get merged and at least push a branch so you can see what I'm doing at least. After that I want to dive in to this annoying scrolling problem. For me it already renders faster without the hidden ember-collections in the definitions.

BryanCrotaz commented 9 years ago

Aha!

BryanCrotaz commented 9 years ago

I'll start doing the draggable column boundaries

BryanCrotaz commented 9 years ago

If we can get what we have plus resize columns then we just need tests for a first release

shaunc commented 9 years ago

:)

shaunc commented 9 years ago

ok -- pushed; now on to scrolling

BryanCrotaz commented 9 years ago

default headers are broken. investigating

BryanCrotaz commented 9 years ago

column resize worked first time. The architecture seems to be working.

You can mark a column as resizable: false

BryanCrotaz commented 9 years ago

age is marked as not resizable in the dummy app

shaunc commented 9 years ago

excellent -- pulled and had fund resizing. How is rendering speed for you now?

BryanCrotaz commented 9 years ago

Much faster. But row ordering is completely broken and some rows have no data in them. Startup speed is slow (about 1 second on my machine to fully render)

BryanCrotaz commented 9 years ago

Just got booked to do a talk on this component on 10th Sept at Ember London. There's some really interesting techniques in here.

shaunc commented 9 years ago

Wow -- great!

I'm working on ordering now. VS startup speed perhaps we should try turning off rendering of display table until definitions have been processed.

shaunc commented 9 years ago

Ordering I should be able to get working but won't be ideal. For further improvement make want to derive from ember-collection so we can take advantage of the same map it is using.

BryanCrotaz commented 9 years ago

hmm. Can we not have a body-row component which deals with laying out the row so that ember-collection only deals with row ordering?

shaunc commented 9 years ago

I have added and then deleted a body-row three times. :) ... it doesn't really help the situation. Currently ember-collection is already only dealing with row ordering. Just that it expects rows to "re-render" when it remaps, and as for me rerendering means taking DOM notes off the shelf from the definition, I also have to put them back on the shelf when I'm done with them -- that is what I'm working on now.

BryanCrotaz commented 9 years ago

aha - they were dissappearing down the worm-plug-hole?

shaunc commented 9 years ago

Yes -- and so the old contents is still there out of order.

BryanCrotaz commented 9 years ago

I've implemented min and max column widths both in column def and in css. I'm going to make styling behave properly re CSP and then I think rendering rows is the only thing left

shaunc commented 9 years ago

Speed-wise -- we'll see how it looks. It could be further improved if (a subclass of) ember-collection moved the nodes itself rather than asking for a rerender.

BryanCrotaz commented 9 years ago

I wonder if having body-row makes your problem neater if not easier as it's a clean place to put the wormhole behaviour

BryanCrotaz commented 9 years ago

I think slightly slow is fine for now - let's build tests once we have a v1 functionality. I'm amazed at how fast this has come together. Liking component-style building

shaunc commented 9 years ago

right now I've got it pretty well encapsulated:

The definition cell is responsible for getting node:

getCellElement(rowIndex) {
  var element = this.element;
  if (element == null || element.childNodes == null) {
    return null;
  }
  var {'_body.offset': offset, '_body.limit': limit } = this.getProperties(
    '_body.offset', '_body.limit');
  if (rowIndex < offset || rowIndex >= offset + limit) { return null; }
  return element.getElementsByClassName('eg-body-cell')[rowIndex - offset];
},

The rendering cell asks for the contents and moves into place

didInsertElement: function() {
  this._super.apply(this, arguments);
  var source = this.get('column._zones.body.source');
  var sourceElement = source.getCellElement(this.get('rowIndex'));
  this.moveChildren(sourceElement, this.element);
},
moveChildren: function (source, target) {
  if (source == null || target == null) { return; }
  while (source.childNodes.length > 0) {
    target.appendChild(source.childNodes[0]);
  }
}
BryanCrotaz commented 9 years ago

blue header is defined in dummy app styling to confirm that app can override styling

BryanCrotaz commented 9 years ago

feels a bit dodgy that the definition cell is dealing with offsets and class names. shouldn't it just grab its entire block?

shaunc commented 9 years ago

I'm sorry -- thats not the definition cell. Thats the definition body. Your right that I could break it into two steps -- definition body gets cell component, then cell component gets contents. But currently there is no cell component and as this would be the only logic in it its not so bad I think but can clean up if you like. However, first I have to finish up the "put the nodes back" code.

BryanCrotaz commented 9 years ago

if you look at how I've done the header,

parentView.set('_column._zones.header.element', this.get('element'));

I'm just grabbing the whole element in the definition

Then eg-render/eg-header-cell moves its children:

  renderHeader: function() {
    var header = this.get('_header');
    if (header)
    {
        var sourceElement = header.element;
        var destinationElement = this.get('element');
        var node = sourceElement.firstChild;
        var lastNode = sourceElement.lastChild;
        while(node) {
          destinationElement.insertBefore(node, null);
          node = node !== lastNode ? lastNode.parentNode.firstChild : null;
        }
      }
  },
BryanCrotaz commented 9 years ago

probably

moveChildren: function (source, target) {
if (source == null || target == null) { return; }
while (source.childNodes.length > 0) {
target.appendChild(source.childNodes[0]);
}

should be in a mixin as the header and footer could reuse the same code

shaunc commented 9 years ago

(We would need to add a (say) eg-body/eg-cell ... marginal if you ask me)

shaunc commented 9 years ago

mixin: +1

BryanCrotaz commented 9 years ago

ok, let's review when you're done

shaunc commented 9 years ago

ok -- there you go. header looks good. Its still a bit too lazy -- scroll lags behind. Simplest way to fix would probably to draw the table (in a window that blocks view of top and bottom) a few rows larger than it was then put sentinel rows at top and bottom so start and end of table arent obscured.

shaunc commented 9 years ago

I'm also very surprised it works so well already. One ceveat is its pointing at my private copy of ember-collection, which has some bug fixes still sitting in a PR. Still very good -- I think you've done a great job filling out the architecture.

Take a look at what I've done. I can put in eg-render/body-row and/or eg-body/eg-cell if you think its worthwhile.

shaunc commented 9 years ago

btw -- should we remove eg-render components from app/ as they are not part of the public interface?

shaunc commented 9 years ago

one small thing with header drag: how to resize last cell

BryanCrotaz commented 9 years ago

I tried removing eg-render components, but then they're not found by the resolver. Would be nice to find a way around that.

I forgot about the last cell! Do you think the last cell should fill remaining space? That would make sense in a normal table view. min-width settings would work to make the next column collapse when it reached its limit.

Header resize also lags behind a little - much more than in ember-split-view. I'm not too concerned right now.

BryanCrotaz commented 9 years ago

list-view had functionality for providing a scroll buffer either side of the visible window. Does ember-collection not have that?

BryanCrotaz commented 9 years ago

scroll is broken with your new code. First page renders correctly, then nothing else as I scroll down

image

shaunc commented 9 years ago

hmm.. not what I see... perhaps -- can you pull the latest shaunc/ember-collection?

BryanCrotaz commented 9 years ago

can you change package.json to point to the correct branch?

BryanCrotaz commented 9 years ago

ah! I see - you've fixed ember-collection since I last npm installed. npm updating...

shaunc commented 9 years ago

buffer: it keeps a buffer of old nodes, but tells to rerender just as approaches screen. Arguably a bug.

BryanCrotaz commented 9 years ago

and our rerender is slow?

shaunc commented 9 years ago

I think its rather that ember executes the hooks with a lag

BryanCrotaz commented 9 years ago

so it's already on screen when the hook kicks in?

shaunc commented 9 years ago

yes -- exactly. Is it working for you now? (My son awaits my reading to him :)) Just pushed a small fix to give cells height.

BryanCrotaz commented 9 years ago

scrolling slowly is fine after update, but fast scroll gives lots of empty rows