apexcharts / Blazor-ApexCharts

A blazor wrapper for ApexCharts.js
https://apexcharts.github.io/Blazor-ApexCharts
MIT License
794 stars 91 forks source link

jsObjectReference returning null when calling UpdateOptionsAsync or UpdateSeriesAsync #350

Closed mwerberacs closed 9 months ago

mwerberacs commented 9 months ago

I recently upgraded the ApexCharts nuget package from 0.9.20-beta to 2.1.0. Upon doing so, my team is now encountering consistent errors being thrown when calling UpdateOptionsAsync or UpdateSeriesAsync due to a null value.

blazor.server.js:1 [2023-12-01T15:32:01.589Z] Error: System.ArgumentNullException: Value cannot be null. (Parameter 'jsObjectReference') at Microsoft.JSInterop.JSObjectReferenceExtensions.InvokeVoidAsync(IJSObjectReference jsObjectReference, String identifier, Object[] args) at ApexCharts.ApexChart`1.InvokeVoidJsAsync(String identifier, Object[] args) at ApexCharts.ApexChart`1.UpdateSeriesAsync(Boolean animate) at ApprenticeshipComplianceSystem.Modules.ApprenticeManager.ApprenticeEvaluations.OnParametersSetAsync() in C:\Users\Mariah.Werber\source\repos\ApprenticeshipComplianceSystem\ApprenticeshipComplianceSystem\Modules\Managers\ApprenticeManager\TabPanels\Evaluations\ApprenticeEvaluations.razor:line 627 at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task) at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync() at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

Using a try/catch stops the app from crashing and the charts update as normal, but I have a function that prints the error message in the devtools console manually when it falls through to catch and I can see the null value error still happens. I have tried downgrading to 1.0.0 and the issue still persists. Reverting back to 0.9.20-beta fixes this issue entirely.

matt-entrekin commented 9 months ago

I had similar issues related to the series being empty. It was hard to debug because the underlying code in Blazor-ApexCharts using async await. When debugging the Blazor-ApexCharts code, what I saw was a chart's .Series that was an empty collection later became null. That meant I couldn't always rely on Series.Any() to prevent the errors.

I ended up using a heavy-handed approach of replacing my code's references to ApexChart with my custom subclass that prevents the errors.

public class MyApexChart<TItem> : ApexChart<TItem> where TItem : class
{
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        try
        {
            // ApexCharts throws when trying to render a chart without a series.
            if (Series.Any())
            {
                await base.OnAfterRenderAsync(firstRender);
            }
        }
        catch
        {
        }
    }
}
mwerberacs commented 9 months ago

@matt-entrekin Unfortunately the issue isn't the series count; we already have a conditional in place to make sure charts don't render/update unless it has a series. Just to verify though I did test out your suggestion, but I was still getting the error consistently. The issue is that for some reason, blazor_apexchart is null when called by the first if statement in InvokeVoidJsAsync:

private async ValueTask InvokeVoidJsAsync(string identifier, params object[] args)
{
    try
    {
        IJSInProcessObjectReference iJSInProcessObjectReference = blazor_apexchart as IJSInProcessObjectReference;
        if (iJSInProcessObjectReference == null)
        {
            await blazor_apexchart.InvokeVoidAsync(identifier, args);
        }
        else
        {
            iJSInProcessObjectReference.InvokeVoid(identifier, args);
        }
    }
    catch (ObjectDisposedException)
    {
    }
}

which results in the InvokeVoidAsync extension method throwing an ArgumentNullException:

public static async ValueTask InvokeVoidAsync(this IJSObjectReference jsObjectReference, string identifier, params object?[]? args)
{
    if (jsObjectReference is null)
    {
        throw new ArgumentNullException(nameof(jsObjectReference));
    }

    await jsObjectReference.InvokeAsync<IJSVoidResult>(identifier, args);
}
MichaelCastano commented 9 months ago

Just came across the exact same issue, updated from 0.9.13-beta to 2.1.0. I am using Blazor-ApexCharts in a .net 6. Blazor WASM environment.

@mwerberacs where did you put the try/catch? Just around the two Update calls? Edit: works like a charm. Thx for the temorary fix.

Alywan commented 9 months ago

Where do i need to put the try/catch ?

My code breaks here :

        await Chart!.UpdateSeriesAsync(true);
joadan commented 9 months ago

Hello,

I try to add a guard for this asap.

joadan commented 9 months ago

Hi, I have added a guard in Release v2.2.0.

Would be great if you could try it out and let me know if it resolves the issue.

Thank you

MichaelCastano commented 9 months ago

Hi, I just double checked this and the guard seems to work.

I removed the temporary try/catch blocks from my code.

V2.1.0 => Error V2.2.0 => No Error anymore

Thanks for the fast bugfix :)

joadan commented 9 months ago

Thank you!