DataTables with Blazor
DataTables with Blazor
Hi, I'm experimenting with Blazor Single Page Application and I wanted DataTables through JavaScript InterOp.
The App is still the tutorial one, with only a page changed
On my index.htm I put the following function that I call from my razor page Ruoli
function CaricaDataTables(table)
{
$(document).ready(function () {
$(table).DataTable();
});
}
It works perfectly
Except for the fact that when I change page, the filter and the footer remain on the page
Do you have an suggestion on where I'm mistaking ?
Thanks in advace
Replies
Hi @robigit ,
DataTables adds control elements to the DOM around the table - which is what is being left behind. If there are triggers or events for the page change, you could
destroy()
which would remove those elements.Hope that helps,
Cheers,
Colin
Just in case there is someone else out there like me who found themselves here because they are trying out Blazor, but need the answer to be shown explicitly.
Here are all the pieces and the places they need to go in the basic client side app for .Net Core 3.0.0-preview6. In case it's not obvious don't copy the whole code verbatim, the part that is in head needs to be copied into head, etc. I'm just showing the pieces that get the data table into the page and then remove it. As per the suggestion above.
In wwwroot/index.html:
In your copy of FetchData.razor or SomeFile.razor you need:
Nice one - thanks for posting this!
Allan
This example is no longer working for dotnet core 3.0.100-preview8-013656
Yeah, it looks like the call to destroy() is no longer needed, so onbeforeunload isn't needed either. There still needs to be a body tag around the HTML that contains the table. Also Microsoft renamed OnInitAsync to OnInitializedAsync.
Here is the complete code for the two files using the “Blazor WebAssembly App” template in .NET Core 3.0 Preview 8.
wwwroot/index.html:
FetchData.razor:
Hi @toms ,
Thanks for sharing that code, that's helpful.
Cheers,
Colin
@toms
Just downloaded latest version of Blazor and tried to follow your example above.
When using JSruntime.InvokeAsync (same syntax as you had) then I get the error that it cannot convert a string to an object[] (this is for "#example").
Hi @toms
I'm using dotnet core 3.0.100-preview8-013656 I'm trying to get it to work with the "Blazor Server App" version which just has the "_Host.cshtml" razor page and it doesn't have the "index.html" but doesn't work.
With reference to my above post, by "latest" I'm referring to .NET Core 3.0 preview 9 with Blazor preview 9.
Hi @dlasalde@fbchomeloans.com
You can see I was careful to say that my example was a Client Side app, which is simpler because all your code is running in the web browser. As I'm sure you know, Blazor Server Side is a bit more tricky since the C# code is running on the Web Server, but the JavaScript still needs to the be handled at the client. The reason it looks like it doesn't work is because if you use the same code in the server side app, but just put the index.html pieces into _Host.cshtml then what you get is actually more of a dice roll. Try clicking back and forth between the counter page and the FetchData page several times. If your computer system is like mine then eventually you should see it work at least once.
The issue is in OnInitializedAsync().
What I think is happening is the call to get the data is run at the server which is all fine and good.
Then the server is sending the JS call to the client and at the same time in the background sending over the data it received from the previous call. This creates a race condition. If the data gets to the browser first then the table is created and your data table will get the format applied. However if the JS call gets there first then the data table doesn't exist in the browser. Somewhere in the background I'm sure it is spitting out an object not found error and of course the format doesn't get applied.
I don't know of a good way to get around this. The only spot I've found so far is to move the JS call into the OnAfterRenderAsync function, but I'm not sure if that is a good idea. The OnAfterRenderAsync function gets called multiple times. I assume anytime the table is rendered.
At any rate if you want to try it put the code that I added to index.html into _Host.cshtml and then add the following to the FetchData.razor:
Here is the complete code for the two files using the “Blazor Server App” template in .NET Core 3.0 Preview 8. Also for this one I downloaded JQuery and Datatables.net instead of using the CDN. Also I downloaded Blazor.Polyfill and put it in a folder I created called wwwroot\Git, so I could enable my app to work with IE11.
You can get the JQuery and Datatables.net by right clicking on your project in VS and choosing "Add" -> "Client-Side Library...", then type in jquery or datatables.net and select them from the list.
You can download Blazor.Polyfill from here:
https://github.com/Daddoon/Blazor.Polyfill
_Host.cshtml :
FetchData.razor:
@DrGriff
I haven't downloaded Preview 9 yet, so I'm not sure what they "polished" to make it not work. Keep in mind the release date for the non-preview is in two weeks, so they may "polish" it again.
I would look here:
https://devblogs.microsoft.com/aspnet/asp-net-core-and-blazor-updates-in-net-core-3-0-preview-9/
or here:
https://docs.microsoft.com/en-us/aspnet/core/blazor/javascript-interop?view=aspnetcore-3.0
Basically what you need to do is make sure that JQuery works, make sure that the table is created at the client and then make the JS call to apply the table format. I've included in my code above some examples for testing JQuery and JavaScript. If you can find examples for those for preview 9 then you should be able to get it working. I've also included some manual buttons that I've commented out, but they show you how to manually make the calls to apply the Datatables.net format.
@toms
Many thanks for the feedback and the code examples:I'll certainly try that again in a bit.
Not sure if this next bit is contraversial, but one consequence of Blazor is that (in theory at least) it allows the Developer to write client-side code solely in C#, dropping reliance on JavaScript. Might this suggest that in future Blazor developers will eventually be looking for a "Blazor component" version of DataTables as opposed to the current JavaScript implementation?
@DrGriff
Well, I'm not affiliated with Datatables.net or Microsoft, but I think the point of Microsoft adding the JS Interop was so that you could choose to use either depending on which components you prefer. If you want to use a Blazor component there is no need to wait for the future there are free or paid for options out there. It just adds competition and variety.
I still haven't upgraded to Preview 9, so this is just a shot in the dark based on your error, but maybe try changing the java call to this:
and change your JS script to :
@DrGriff
I finally updated to Preview 9 and tested by creating a new app using the Preview 9 client side template which they named “Blazor WebAssembly App”. It worked on my computer using the same code as I did in Preview 8, so I don't know what caused the error.
Maybe try running the command to get the latest templates again. I know I had to run it a couple of times when I first updated to preview 8.
From Console (with admin rights):
dotnet new -i Microsoft.AspNetCore.Blazor.Templates::3.0.0-preview9.19424.4
I cannot use the body element to initiate the table removal because Blazor doesn't connect the <body> with </body> when there is C# code mixed in.
I have implemented the dispose method which does fire when I leave the page. I have alert popups letting me know.
The problem is that the controls are not removed. When I make the same JS interopt call from a button the controls remove nicely so I know the JS code works when called.
Any ideas?
@page "/fetchdata"
@using bm2portal_blazor.Shared
@inject HttpClient Http
@inject IJSRuntime JSRuntime
@implements IDisposable
Weather forecast
This component demonstrates fetching data from the server.
<button class="btn btn-primary" @onclick="@CallRemoveTable">Remove Table</button>
@if (forecasts == null)
{
Loading...
}
else
{
}
@code {
WeatherForecast[] forecasts;
}
Ok, here is what I'm doing to clean up the table wrapper that is left behind.
I implement the Dispose override.
// C# code in the component.
public void Dispose()
{
JSRuntime.InvokeAsync<bool>("TestDataTablesRemove", "#table_id");
}
// JavaScript Function
function TestDataTablesRemove(table) {
$(document).ready(function () {
$(table).DataTable().destroy();
});
Good call on the Dispose override. I knew there had to be a better way. Now that you've pointed it out it seems obvious.
I know this is an old thread but I want to ask a question. I'm running .net core 3.1 with Blazor Server release version and everything works great except for one thing. When I add/remove rows. The grid add the row at the top but doesn't reset, paging, and record count. Anyone one had the same issue and how did you resolve it? I trying to do
$(table).DataTable().ajax.reload();
and $(table).DataTable().ajax.draw();
but neither of them work.
Hey, old post but am kinda stuck at the wrappers left behind - I am a complete noob so forgive my question when i ask where do I add the Dispose override mentioned above?
Since Blazor WebAssembly 3.2.0 now available and officially supported, I've created the fiddle below using the client-side example from Comment_157079 by @toms.
https://blazorfiddle.com/s/dczu8r1f
Excellent, thanks for sharing,
Colin
For a complete tutorial including Blazor source code, check out this post:
https://gmtech.co.za/how-to-add-js-data-tables-to-your-blazor-project/
Check out https://mudblazor.com it has a data table with pagination, sorting and filtering and is very easy to use.
Unfortunately I get an error message in the line await JSRuntime.InvokeAsync<object>("TestDataTablesAdd", "#example"); (from JsFiddle).
Argument 2: cannot convert from 'string' to 'object[]'
What can I do? I have already tried to pass an array char[]. Unfortunately without success.
About help I would be very happy. Many thanks in advance.
Hello guys
Did anyone solve the issue?
Because none of the above solutions worked for me.
@onclick="(()=>EditData(model.Id))"
onclick not working inside table while using jquery datatable