Table component row index

  • 1
  • Question
  • Updated 5 years ago
  • Answered
Hello all,

I have a question about the table component.

Is it possible to render a field in a table row that displays the index of the current row? We tried doing this by creating a custom field on our SF object. I then wrote a custom field renderer to incrementally assign IDs to this field on page load and as the user enters new rows. But I'm seeing strange behavior, and it feels like I'm going about this the wrong way.

All I want to do is display the index of the row in the data object for the model being displayed by the table component. Is there an easy way to do this?

Thanks!
Photo of Robert Mruczek

Robert Mruczek

  • 222 Points 100 badge 2x thumb

Posted 5 years ago

  • 1
Photo of Peter Baeza

Peter Baeza

  • 2,868 Points 2k badge 2x thumb
If you want the current row of the displayed table there is a roundabout way to achieve this by using a custom field renderer and grab the rowIndex. Add any field from the model that you are not currently displaying in the table and set it to ReadOnly and use a custom field renderer RowNo. Create the custom field renderer as an inline JS snippet with the following content:

var field = arguments[0],
$ = skuid.$;

$(document).ready(function() {
setTimeout(function() {
var row = field.element[0].parentElement.parentElement.rowIndex;
skuid.ui.fieldRenderers.TEXT.read(field,field.element[0].parentElement.parentElement.rowIndex);
}, 1000);
});
Note that I had to introduce a delay to get this to work. Otherwise it works on first load but not after load more or re-sorting. Not really sure exactly why but I guess refresh is asynchronous and the order of loading is important. Can't find how to know when to render but I'm sure the Skuid team has a solution for this.

Also this displays the order of the table on screen and not the actual sort order of the model. They might be the same but if you allow sorting and filtering then you would have to come up with a solution for somehow getting the row number from the model instead or maybe using your method of assigning numbers on load. You can probably do this by handling edtior changes instead of using a custom field renderer.
/ Peter
Photo of Peter Baeza

Peter Baeza

  • 2,868 Points 2k badge 2x thumb
Here is a version of the snippet that gets the number from the model instead. Requries the field that it is the renderer for is the Id field.

var field = arguments[0], value = arguments[1]
$ = skuid.$;

$.each(field.model.data,function(i,row){
if(row.Id == value) {
skuid.ui.fieldRenderers.TEXT.read(field,i);
}

});

Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
There's actually an easier way to do it, using a Template component:

1. Drag a Template component into your Table
2. For Label, enter Index
3. For Template, enter {{index}}.
4. Save, then preview.









Photo of Peter Baeza

Peter Baeza

  • 2,868 Points 2k badge 2x thumb
aargh, I actually tried a template first but using {{rowIndex}} and not {{index}}...... Can't find any documentation on row merge template variables, only the global variables, am I missing something.

Also it would be very interesting to hear a explanation on the necessary timing delay in my first sample as the sames issue applies in otther situations as well so it would be good to know how the refresh/rerendering happens i more detail.  
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
No you're not missing anything on Row Merge template variables, they're not documented anywhere yet :(

The reason you had to do a setTimeout in your first example relates to your approach of using the field.element[0].parentElement.parentElement to get the index --- this approach doesn't work because of the "order of rendering", as you guessed. Basically, in order to maximize load time, field.element is not appended to its parent element until AFTER the field renderer is done processing --- so in your custom field renderer code, all of the code is applied to an unattached DOM element --- the DOM element is not yet in the full DOM tree, and so .parentElement is going to be null or empty --- until a few milliseconds later on, when field.element gets appended to the appropriate parent element. The reason that this maximizes table render time is that DOM insert operations are expensive, so we try in Skuid in general to follow a pattern of building out as much of our elements as possible before actually inserting it into the page's DOM tree.
Photo of Peter Baeza

Peter Baeza

  • 2,868 Points 2k badge 2x thumb
Thanks for the explanation Zach. It's a bit confusing that logging field.element to the console will acutally show the attached element but I assume that this is the console trying to be helpful and giving the updated element.

Is there a better solution for waiting until the DOM element is attached to the field renderer than adding a delay?


Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Yeah the fact that the Console always shows the live state of any DOM object, as opposed to what it's state was when you logged it, has been the source of many frustrations for many developers, us included. Very important point to be aware of. One way to get around it is to console log the value of primitives on that object, or to serialize the object to a string and then log the string (of course with huge objects this will not be very helpful).

As far as waiting until the DOM element is attached, no, we don't provide a good alternative to setTimeout right now, that's the best way I know of. Maybe in the future we'll fire an event at the Field and Item level so that you know when the Field's DOM element has been attached to its Item's DOM element, and up the chain.