I'm using a Blazor WebApp with C# and .net 6.In this example I'm using the standard project "Blazor Server App" (VS 2022) for testing.
I built a own "table helper", where I can pass a dataset in the codebehind which is displayed on the page with a single command.The full file is here: Table.cs
using System.Text;using Microsoft.AspNetCore.Components;namespace MarkusH.Modulxo.Webclient.Components{ public class Table { private Columnset _columnset = null; private Dataset _dataset = null; private List<string> _classes = new List<string>(); private string _linkNew = ""; private string _linkEdit = ""; public Table() { AddClasses("table", "table-striped"); } public void SetColumnset(Columnset columnset) { _columnset = columnset; } public void SetDataset(Dataset dataset, string orderByAttributeName = "") { _dataset = dataset; if (!string.IsNullOrWhiteSpace(orderByAttributeName)) { SortRecordsBy(orderByAttributeName); } } public void SortRecordsBy(string orderByAttributeName) { _dataset?.OrderBy(orderByAttributeName); } public void SetLinkNew(string linkNew) { _linkNew = linkNew; } public void SetLinkEdit(string linkEdit) { _linkEdit = linkEdit; } public void AddClasses(params string[] classes) { _classes.AddRange(classes); } public MarkupString ShowComponent() { var stringBuilder = new StringBuilder(); if (_columnset != null) { stringBuilder.Append(BuildTableHeader()); stringBuilder.Append(BuildTableBody()); stringBuilder.Append(BuildTableFooter()); } return (MarkupString)stringBuilder.ToString(); } private string BuildTableHeader() { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"<table class='{string.Join(" ", _classes)}'>"); stringBuilder.AppendLine("<thead><tr>"); foreach (var column in _columnset.Columns) { stringBuilder.Append($"<th @onclick='() => SortRecordsBy({column.AttributeName})'>{column.Header}</th>"); } stringBuilder.Append("<th>"); if (!string.IsNullOrEmpty(_linkNew)) { stringBuilder.Append($"<a href='{_linkNew}'>New</a>"); } stringBuilder.Append("</th>"); stringBuilder.AppendLine("</tr></thead>"); return stringBuilder.ToString(); } private string BuildTableBody() { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("<tbody>"); if (_dataset != null && _dataset.Records.Count > 0) { stringBuilder.Append(BuildTableBodyFromData()); } else { stringBuilder.Append(BuildTableBodyNoRecords()); } stringBuilder.AppendLine("</tbody>"); return stringBuilder.ToString(); } private string BuildTableBodyFromData() { var stringBuilder = new StringBuilder(); foreach (var record in _dataset.Records) { stringBuilder.AppendLine("<tr>"); foreach (var column in _columnset.Columns) { stringBuilder.Append($"<td>{record.GetAttributeValue<object>(column.AttributeName).ToString()}</td>"); } stringBuilder.Append("<td>"); if (!string.IsNullOrEmpty(_linkEdit)) { stringBuilder.Append($"<a href='{_linkEdit.Replace("%id%", record.Id.ToString())}'>Edit</a>"); } stringBuilder.Append("</td>"); stringBuilder.AppendLine("</tr>"); } return stringBuilder.ToString(); } private string BuildTableBodyNoRecords() { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("<tr>"); stringBuilder.Append($"<td colspan='{_columnset.Columns.Count + 2}'>No data</td>"); stringBuilder.AppendLine("</tr>"); return stringBuilder.ToString(); } private string BuildTableFooter() { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("</table>"); return stringBuilder.ToString(); } }}The implementation in codebehind looks like: Countrylist.razor.cs
...protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { await addressbookService.InitMoxClient(); if (ForwardToLoginPageIfNotAuthenticated(addressbookService)) { return; } var countries = addressbookService.GetCountryList(); _countryTable.SetDataset(new Dataset(new List<MoxBaseRecord>(countries)), "Countryname"); StateHasChanged(); } }...As you can see, the table headers should sort the data within - but the onclick-function-call is not rendered correctly.
I found multiple topics addressing more or less the same problem, but the most hints I found were to loop trough the objects on the page instead of the code-behind - but I want to build a generic component to use on multiple pages - so I couldn't figerout how to achive the same result.
It would be great if someone can provide a hint/solution to solve the issue.
Thanks and regards
Markus