Dojo Data Grid – Part 35: Suppressing Blank Rows Due to Readers Fields

Over the last few months, I’ve received several messages and read several posts trying to figure out how to suppress blank rows in a grid due to Readers field security on the documents in the underlying view. In this post, I’ll share an anticlimatcally-simple solution to this white whale of a problem.

Dojo Data Grid Series

Dojo Grids in XPages — All Blog Posts

The Problem

When you have a Dojo data grid that displays entries from a view via a REST service, you will see one row for each entry in the underlying view. If there are documents that are hidden from the user due to readers field security, you will still see a row for each of those documents, but they will be virtually blank (displaying … in each cell).

So, if you have 10,000 documents in a view, but the user can only see 100 of them, there will be 9,900 blank lines to scroll through in the view.

It’s a maddening issue. I’ve heard multiple people say that they stopped trying to use a dojo grid because of this.

Attempted Solutions

I spent hours trying to handle this issue in numerous ways.

I tried code that tried to check the row contents (similarly to this post) to apply a css class to hide it when blank, but I found that *every* row starts out with the default cell content (…) and then, on a second pass, fills in the real data. When I looked for an empty row and applied the class, it would hide every row before the valid ones were filled in.

I made several attempts at writing code that scanned the current set of records in memory (a block of rows the same size as the rowsPerPage property), but I found that the block of rows in memory was constantly shifting, so I couldn’t check the current block and suppress rows as needed dynamically.

I also noticed that the grid’s row.index property and the @Position attribute of a grid entry got out of synch as soon as there was a document hidden due to reader security. However, it didn’t display the blank rows inline — it moved them all to the end. This was also very problematic in checking data and determining what to suppress.

Ultimately, I realized that I can’t help the fact that the built-in REST service appears to look at view meta data and tell the REST service that it’s returning the number of elements corresponding to the total number of documents in the underlying view, regardless of the security.

A Solution

Then it occurred to me that I wouldn’t have to try to scan through the rows in memory if the entire set was in memory. Then it would just be a matter of counting how many actual rows were generated and hiding the rest.

I noticed that the REST service doesn’t actually include blank rows, but it does include a row count at the beginning that tells the grid how many rows to render. The grid will include all valid rows and then fill in the rest with blank rows.

To solve the problem, you can load all rows into memory and the use the onStyleRow event handler (see this post for more info) to hide the blank rows (which come after the actual row count has been reached).

Follow these two steps to implement the solution:

1) Set the rowsPerPage property of the grid to a number that is equal to (or greater than) the number of rows that could be included in the grid

2) Put this code in the onStyleRow property of the grid:

var row = arguments[0];

if (row.index >= restViewItemFileService['_items'].length) {
 row.customStyles += 'display:none;';
}

This assumes that you’re using a restViewItemFileService type of REST service. The second line would be different for a viewJsonService.

In the code above, ‘restViewItemFileService’ is the name of the REST service. Change it to match the ID of your rest service.

All in all, I spent hours and probably wrote a few hundred lines of code in various attempts in order to come up with what was ultimately a property change and a 4-line solution!

Caveat

Performance is certainly a big factor in whether this solution will work in your grid, because all documents must be loaded into memory rather than pre-loading a small chunk and then loading the rest on demand.

Another Potential Approach

Another approach that may work (but one that I have not yet tried) would be creating a custom REST service that only returns rows based on the current user’s security. That would seem to be a valid approach, but this post was focused on solving the problem with the provided view REST service types.

8 responses to “Dojo Data Grid – Part 35: Suppressing Blank Rows Due to Readers Fields”

  1. edm00se says :

    I hate to admit it, but I’m in the category of those who turned away (are waiting until an improved solution) due to the blank rows from Readers field enforcement.

    I can say I’m excited to see any progress in that department, as it would probably replace a good number of xp:viewPanel elements; as your Data Grid series has highlighted the many other excellent features.

  2. Alan Hurt says :

    Is this a problem with Dojo grid in XPages while using a REST service? Curious, as I use Dojo grids in ‘classic’ Domino applications and pull data via the Domino Data Service (REST) and have never seen this issue at all?

    • Brad Balassaitis says :

      The issue I’m referring to is using the REST service control with the viewItemFileService or viewJsonService types.

      Definitely not an inherent rest issue. Just a quirk in how those view services return a row count.

  3. Aaron Brake (@AaronDBrake) says :

    Brad, This works great for hiding the rows, but then I’m hitting a situation wherein when I mouse over the rows they hide. I don’t know what would change between the initial row loading and the subesquent onMouseOver event (and I’m also guessing now that onMouseOver is firing an onRowStyle event) but do you know why this might be happening?

    Thanks

  4. Carlos Moran says :

    I’ve noticed that blank lines are not returned when searching. Only documents that match search criteria and are accessible are returned…
    So, why not do always a search by something is always true? For instance, look for a system field: “[$UpdatedBy] is present”.
    It’s slower, but it works!

Leave a comment