Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide an EmptyData template for QuickGrid for display when no records are bound #59078

Open
1 task done
htmlsplash opened this issue Nov 20, 2024 · 10 comments
Open
1 task done
Labels
area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-blazor-quickgrid
Milestone

Comments

@htmlsplash
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

With the newest version of QuickGrid (v9.0) when rendering empty rows it now includes td elements. These empty td elements use the same CSS classes when data bound rows are rendered. This causes an empty data grid to display row lines or other styling on empty rows.

In addition, sometimes the classes that are specified on the QuickGrid tag (ie table tag) may apply row/cell styling causing same side effect (ex Bootstrap table table-* classes). The end result is again that lines are displayed per each empty row.

Here's the original issue about this: #57199

Describe the solution you'd like

If you have to render empty rows then:
One solution is to introduce another set of CSS classes that we can style on empty cells. This would allow the author specify classes that negate the styles that are inherited from applied CSS styles at the table element (Ex bootstrap table class styles).
Is there better solution to this?

Ultimately, I prefer to see QuickGrid to have an EmptyData template that user can specified if there are no records bound to the datagrid.

Additional context

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-blazor Includes: Blazor, Razor Components label Nov 20, 2024
@htmlsplash htmlsplash changed the title Update QuickGrid, when rendering empty rows, don't render them styled Update QuickGrid, Fix the issue when rendering empty rows, so that they don't render styled Nov 20, 2024
@MackinnonBuck MackinnonBuck self-assigned this Nov 20, 2024
@javiercn
Copy link
Member

@htmlsplash thanks for contacting us.

Is it not possible for you to use to style the elements?

td:empty {

}

@htmlsplash
Copy link
Author

htmlsplash commented Nov 20, 2024

"Is it not possible for you to use to style the elements?" - That's a workaround, yes. Question, is it semantically correct to put row/td styles intended for rows with data on empty rows that you render for whatever reason you need to render them.

How about adding EmptyData template? Currently, there's no way without extra coding to add a user message stating: Query return no results. This a very common use case for using any iterative control.

@svogel123
Copy link

svogel123 commented Nov 21, 2024

The problem is, if a cell is empty in a row, it destroys the whole layout.

This css is my hack:

tr:has(> td:not(:empty)) > td {
    display: table-cell;
}

td:empty {
    display: none;
}

@htmlsplash
Copy link
Author

htmlsplash commented Nov 21, 2024

I guess, that brings up a question:
Why do we need these empty rows, what layout are we trying to preserve when there is no data.
If there's no data bound, we should not display any empty rows or headers for that matter, we should not even render the table. And if the user wants to display an empty data message, render that template fragment.
All the solutions so far provided are workarounds (hacks) that I require to write every time I use the QuickGrid.

@javiercn
Copy link
Member

The rows are rendered because otherwise anything that is below the table moves when there aren't enough rows. I believe the goal is you can give the rows a fixed height so that your layout doesn't shift.

@htmlsplash
Copy link
Author

Okay ... Honestly, if preserving the layout is so important, then at least give others an option to opt out from this logic. For example, using EmptyData template. If that templates is specified, then only content within the template is rendered and nothing else. Then you have best of both worlds.

@danroth27
Copy link
Member

Ultimately, I prefer to see QuickGrid to have an EmptyData template that user can specified if there are no records bound to the datagrid.
...
If that template is specified, then only content within the template is rendered and nothing else.

@htmlsplash Since your request is specifically about adding an EmptyData template feature, I've updated the title of this issue accordingly. To be clear though, you would still see empty rows rendered to fill out the page if some records are bound and you are using a paginator. That issue, which is tracked by #57199 would still need to be handled with custom styling.

@danroth27 danroth27 changed the title Update QuickGrid, Fix the issue when rendering empty rows, so that they don't render styled Provide an EmptyData template for QuickGrid for display when no records are bound Nov 21, 2024
@danroth27 danroth27 added enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-blazor-quickgrid and removed investigate labels Nov 21, 2024
@htmlsplash
Copy link
Author

"you would still see empty rows rendered to fill out the page if some records are bound " - That's fine, but if there is no data bound (ie your query returns 0 records) I don't want to see any rows generated if I have specified an EmptyData template.

@MorneZaayman
Copy link

This is how my table renders when there is no data:
Image

I would like to render something like:
Image

Unfortunately, I cannot hide the grid and show the message instead because I still need the filters above the grid to display. Sometimes no data is being returned because of the filter(s) set, and users need access to the filters to change them again. Having the option to supply an Empty Data template would be the perfect solution in my opinion.

vladislav-karamfilov added a commit to vladislav-karamfilov/HrAspire that referenced this issue Nov 22, 2024
@JaquesBotha
Copy link

How to Fix Empty <tr> Rows in Blazor QuickGrid with PaginationState

Just My Take On This and It WORKS for me!

Problem Overview
When using Blazor's QuickGrid with PaginationState, developers might encounter an issue where the grid renders empty <tr> rows during initial load or when no data is present. This behavior occurs because QuickGrid pre-renders rows based on the ItemsPerPage setting in PaginationState. However, rows without data do not contain the expected aria-rowindex attribute, making it challenging to differentiate between placeholder rows and actual rows with data.

This leads to:

  • Empty <tr> rows being visible to users.
  • Difficulty in targeting these rows for styling or removal.

Proposed Solution

The solution involves dynamically monitoring the grid’s DOM and processing rows to:

  1. Add custom classes (e.g., tw-group for TailwindCSS). Note: I'm using a tw- prefix within my Tailwind.
  2. Hide rows without the aria-rowindex attribute.
  3. Reapply logic whenever the grid updates (e.g., data loading, pagination, or filtering).

This approach uses TypeScript with a MutationObserver to ensure the grid is processed correctly, regardless of rendering timing or updates.


Why TailwindCSS?

This example uses TailwindCSS to style and hide elements dynamically. Specifically:

  • The tw-hidden class is used to hide empty rows in the grid.
  • The tw-group class adds hover group styling for dynamic row animations.

If you’re using Bootstrap, you can achieve similar results by replacing tw-hidden with d-none or writing custom CSS classes to apply display: none. However, inline styles or custom CSS for these operations are not recommended because they reduce maintainability and scalability.


TypeScript Solution

Here’s the TypeScript code to address the issue. It:

  • Monitors the grid for changes using a MutationObserver.
  • Hides rows without the aria-rowindex attribute.
  • Optionally adds hover animations for buttons inside rows.
/**
 ** TypeScript Function: observeQuickGridRows
 * 1. Adds the `tw-group` class to all <tr> elements for styling.
 * 2. Hides rows without the `aria-rowindex` attribute.
 * 3. Monitors the grid for DOM changes and reprocesses rows as needed.
 */

function observeQuickGridRows(): void {
    const grid = document.querySelector('.quickgrid tbody'); // Target the grid's tbody

    if (!grid) {
        console.warn("Grid tbody not found.");
        return;
    }

    // Function to process rows
    const processRows = () => {
        const rows = grid.querySelectorAll('tr');

        rows.forEach(row => {
            // Add the `tw-group` class to all rows
            row.classList.add('tw-group');

            // Hide rows without `aria-rowindex`
            const hasRowIndex = row.hasAttribute('aria-rowindex');
            if (!hasRowIndex) {
                row.classList.add('tw-hidden'); // TailwindCSS hidden class
            }
        });

        console.log("QuickGrid rows processed: Added `tw-group` and hidden empty rows.");
    };

    // Process rows initially
    processRows();

    // Set up a MutationObserver to observe changes in the grid's tbody
    const observer = new MutationObserver(() => {
        console.log("Grid updated, reprocessing rows...");
        processRows();
    });

    observer.observe(grid, { childList: true, subtree: true }); // Observe for added/removed rows
}

export { observeQuickGridRows };

Blazor Integration

In the Blazor component, integrate the TypeScript function using JSRuntime and invoke it in the OnAfterRenderAsync lifecycle method. This ensures the function runs after the grid is rendered:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        // Start observing and processing rows in the QuickGrid
        await JSRuntime.InvokeVoidAsync("observeQuickGridRows");
    }
}

Make sure the grid has a unique selector (e.g., id or class) in your Razor file:

<QuickGrid id="myGrid" ItemsProvider="@_dataProvider" Pagination="@pagination">
    @ChildContent
</QuickGrid>

Note: I'm not using id I'm running mine straight from the default .quickgrid tbody css class set.

Webpack Integration

To use the TypeScript function, include it in your project and bundle it with Webpack. Here’s an example Webpack configuration to compile the TypeScript into your bundle.js:

module.exports = {
    entry: './wwwroot/js/grid-utils.ts',
    output: {
        filename: 'bundle.js',
        path: __dirname + '/wwwroot/js'
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                use: 'ts-loader',
                exclude: /node_modules/
            }
        ]
    },
    resolve: {
        extensions: ['.ts', '.js']
    }
};

Cleanup Considerations

Since the MutationObserver dynamically monitors changes in the grid’s DOM, you typically don’t need to clean up rows manually. The observer ensures that stale rows are hidden or processed whenever changes occur. However, you should ensure:

  1. Observer Disconnection:

    • If the grid component is destroyed or removed, disconnect the observer to avoid memory leaks:
      observer.disconnect();
      console.log("Observer disconnected.");
  2. Minimal DOM Alterations:

    • Avoid permanently removing rows from the DOM unless necessary, as the grid may rely on these rows for updates (e.g., when new data is loaded).

Why This Solution Works

  1. Precision: The aria-rowindex attribute reliably identifies rows with data.
  2. Dynamic Updates: The MutationObserver ensures rows are reprocessed whenever the grid updates.
  3. Non-Intrusive: This solution works entirely via DOM manipulation, without requiring modifications to QuickGrid.
  4. Reusability: The function can be applied to other grids with similar behavior.

How to Test

  1. Load the page with QuickGrid and observe that rows without data are hidden immediately.
  2. Trigger actions like pagination or data loading and verify that:
    • Rows are reprocessed dynamically.
    • Only rows with aria-rowindex remain visible.

This solution provides a robust fix for the empty row issue in Blazor’s QuickGrid. If you’re experiencing this problem, let me know if this helps or if further refinements are needed!

@mkArtakMSFT mkArtakMSFT added this to the Backlog milestone Nov 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-blazor-quickgrid
Projects
None yet
Development

No branches or pull requests

8 participants