Skip to content

Changed css classes assignment in RenderPlaceholderRow #62709

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix test and fix css styles
  • Loading branch information
dariatiurina committed Jul 16, 2025
commit 56536c1792030e1cc5d86ce460a6dadecc400e81
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,8 @@
@foreach (var col in _columns)
{
var hasCustomPlaceholder = col.PlaceholderTemplate is not null;
var cssClass = hasCustomPlaceholder
? "@ColumnClass(col)"
: "grid-cell-placeholder @ColumnClass(col)";

<td class="@cssClass" @key="@col">
@{ col.RenderPlaceholderContent(__builder, placeholderContext); }
</td>
var placeholderClass = hasCustomPlaceholder ? "" : "grid-cell-placeholder";
<td class="@placeholderClass @ColumnClass(col)" @key="@col">@{ col.RenderPlaceholderContent(__builder, placeholderContext); }</td>
Copy link
Preview

Copilot AI Jul 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider trimming the combined class string to avoid leading whitespace when placeholderClass is empty, for example using class="@($"{placeholderClass} {ColumnClass(col)}".Trim())".

Suggested change
<td class="@placeholderClass @ColumnClass(col)" @key="@col">@{ col.RenderPlaceholderContent(__builder, placeholderContext); }</td>
<td class="@($"{placeholderClass} {ColumnClass(col)}".Trim())" @key="@col">@{ col.RenderPlaceholderContent(__builder, placeholderContext); }</td>

Copilot uses AI. Check for mistakes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This not only affects the ... but also the opacity. (See https://github.com/dotnet/aspnetcore/blob/main/src/Components/QuickGrid/Microsoft.AspNetCore.Components.QuickGrid/src/Themes/Default.css).

I think that rather than conditionally adding/removing the class (which will make things harder for us in the future), we should keep the class and add an extra class (let's say "default" for the discussion but find a better name).

Something like

.quickgrid[theme=default] > tbody > tr > td.grid-cell-placeholder.default:after {
    content: '\2026';
    opacity: 0.75;
}

This more closely follows "BEM" (Block-Element-Modifier) and essentially still allows people to target the placeholder indistinctively if they want to.

}
</tr>
}
Expand Down
25 changes: 15 additions & 10 deletions src/Components/test/E2ETest/Tests/VirtualizationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,28 +113,33 @@ public void AlwaysFillsVisibleCapacity_Async()
[Fact]
public void PlaceholdersHaveCorrectValue_Async()
{
Browser.MountTestComponent<VirtualizationQuickGrid>();
var component = Browser.MountTestComponent<VirtualizationQuickGrid>();

var finishLoadingButton = Browser.Exists(By.Id("finish-loading-button"));

finishLoadingButton.Click(); //not waiting

Browser.True(() => Browser.Exists(By.Id("loadDone")).Text != "111");
var startLoadingButton = Browser.Exists(By.Id("start-loading-button"));
//Load the initial data.
finishLoadingButton.Click();

Browser.True(() => GetItemCount() > 0);
Browser.Equal(0, () => GetPlaceholderCount());

//Start loading the second set of data to check for placeholders.
startLoadingButton.Click();
Browser.ExecuteJavaScript("const container = document.getElementById('async-container'); container.scrollTop = container.scrollHeight * 0.5;");

Browser.Equal(0, () => GetItemCount());
Browser.True(() => GetPlaceholderCount() > 0);

//test that the other placeholder has ...
Browser.Equal("LOADING DATA", () => Browser.Exists(By.CssSelector(".async-placeholder")).Text);

Assert.Equal("\"…\"", Browser.ExecuteJavaScript<string>(@"
const p = document.querySelector('td.async-id');
return p ? getComputedStyle(p, '::after').content : null;"));
Assert.Equal("none", Browser.ExecuteJavaScript<string>(@"
const p = document.querySelector('td.async-second');
return p ? getComputedStyle(p, '::after').content : null;"));
Browser.Equal("LOADING DATA", () => Browser.Exists(By.CssSelector(".async-second .async-placeholder")).Text);

int GetItemCount() => Browser.FindElements(By.CssSelector("#async-container tbody tr:not(:has(.grid-cell-placeholder))")).Count;
int GetPlaceholderCount() => Browser.FindElements(By.CssSelector(".grid-cell-placeholder")).Count;
int GetItemCount() => Browser.FindElements(By.CssSelector("#async-container tbody td.async-id:not(.grid-cell-placeholder)")).Count;
int GetPlaceholderCount() => Browser.FindElements(By.CssSelector("#async-container tbody .async-id.grid-cell-placeholder")).Count;
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,78 +3,80 @@

@if (RendererInfo.IsInteractive)
{
<button id="finish-loading-button" @onclick="@(async () => await FinishLoadingAsync(200))">Finish loading</button>
}
<br/>
<button id="finish-loading-button" @onclick="@(() => FinishLoading(200))">Finish loading</button>
<button id="start-loading-button" @onclick="@(() => StartNewAsyncLoad())">Start new load</button>

@if (boolLoad != "no condition")
{
<p id="loadDone">@boolLoad</p>
}
<br/>

<div id="async-container" style="height: 500px; overflow-y: auto;">
<QuickGrid @ref="asyncGrid" TGridItem="DataItem" ItemsProvider="GetItemsAsync" Virtualize="true" ItemSize="25">
<PropertyColumn Property="@(p => p.Id)" class="async-id">
</PropertyColumn>
<PropertyColumn Property="@(p => p.SecondNum)" class="async-second">
<PlaceholderTemplate>
<strong class="async-placeholder">LOADING DATA</strong>
</PlaceholderTemplate>
</PropertyColumn>
</QuickGrid>
</div>

<div id="async-container" style="height: 500px; overflow-y: auto;">
<QuickGrid @ref="asyncGrid" TGridItem="DataItem" ItemsProvider="GetItemsAsync" Virtualize="true" ItemSize="25">
<PropertyColumn Property="@(p => p.Id)" class="async-id">
</PropertyColumn>
<PropertyColumn Property="@(p => p.SecondNum)" class="async-second">
<PlaceholderTemplate>
<strong class="async-placeholder">LOADING DATA</strong>
</PlaceholderTemplate>
</PropertyColumn>
</QuickGrid>
</div>


}

@code {
record DataItem(int Id, int SecondNum);

QuickGrid<DataItem> asyncGrid;

int asyncTotalItemCount = 200;
int asyncCancellationCount = 0;
string boolLoad = "no condition";

TaskCompletionSource asyncTcs = new TaskCompletionSource();

private async ValueTask<GridItemsProviderResult<DataItem>> GetItemsAsync(GridItemsProviderRequest<DataItem> request)
{
var loadingTask = asyncTcs.Task;
var registration = request.CancellationToken.Register(() => CancelLoadingAsync(request.CancellationToken));
var registration = request.CancellationToken.Register(() => CancelLoading(request.CancellationToken));

try
{
await loadingTask.WaitAsync(request.CancellationToken);

await loadingTask;
var items = Enumerable.Range(request.StartIndex, request.Count ?? 200)
.Select(i => new DataItem(i, i * 2))
.ToArray();

registration.Dispose();
return GridItemsProviderResult.From(items, asyncTotalItemCount);
}
catch (OperationCanceledException)
{
throw;
}
finally
{
registration.Dispose();
}
}

var items = Enumerable.Range(request.StartIndex, request.Count ?? 200)
.Select(i => new DataItem(i, i * 2))
.ToArray();

return GridItemsProviderResult.From(items, asyncTotalItemCount);
void StartNewAsyncLoad()
{
asyncTcs = new TaskCompletionSource();
StateHasChanged();
}

async Task FinishLoadingAsync(int totalItemCount)
void FinishLoading(int totalItemCount)
{
asyncTotalItemCount = totalItemCount;
asyncTcs.SetResult();
asyncTcs = new TaskCompletionSource();

if (asyncGrid is not null)
{
await asyncGrid.RefreshDataAsync();
boolLoad = "condition";
}
else
{
boolLoad = "asyncGrid null";
}
StateHasChanged();
}

void CancelLoadingAsync(System.Threading.CancellationToken cancellationToken)
void CancelLoading(System.Threading.CancellationToken cancellationToken)
{
asyncTcs.TrySetCanceled(cancellationToken);
asyncTcs = new TaskCompletionSource();

asyncCancellationCount++;

StateHasChanged();
}
}
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy