Megabit / Blazorise

Blazorise is a component library built on top of Blazor with support for CSS frameworks like Bootstrap, Tailwind, Bulma, AntDesign, and Material.
https://blazorise.com/
Other
3.29k stars 531 forks source link

Object reference not set to an instance on Chart #590

Closed jaimunday closed 4 years ago

jaimunday commented 4 years ago

I'm having an issue trying to use the Chart function in a Blazor Server app. I have followed everything in: https://blazorise.com/docs/extensions/chart/ as well as the "getting started" part. When the page trys to render the <LineChart @ref="LineChart" TItem="float /> item, I receive the "Object reference not set to an instance.." error. I can instead use: LinceChart<float> LineChart = new LineChart<float>(); however i then get JSInterop errors on the .Update() call and have seen on here it shouldn't be done this way. I am obviously missing something basic but for the life of me can't see it.

stsrki commented 4 years ago

@jaimunday

You're missing the double quote on TItem: <LineChart @ref="LineChart" TItem="float" />

Without more information I cannot know whats the problem. Can you post full example for Chart, including how you define Data and Options?

jaimunday commented 4 years ago

Apologies, that was a copy/paste error. Below is the full page.

Basically i present a dropdown to the user to choose an option, i am then pulling sales data from a database of the Financial Year. Labels are the month. Data is the $ values.

hope this helps


@using ProductionReporting.Data
@using Microsoft.AspNetCore.Authentication.AzureAD
@using System.Xml;
@using System.Xml.Linq;

@inject AuthenticationStateProvider  AuthenticationStateProvider

@inherits OwningComponentBase

<AuthorizeView>
    <Authorized>

        @if (sites == null)
        {
            <!-- Show this if the current user has no data... yet... -->
            <p><em>Loading...</em></p>
        }
        else
        {
            <label>Select a site:</label>
            <select name="site" class="smallInput" @onchange="GetSales">
                <option value="0">--Select a site--</option>
                @foreach (var s in sites)
                {
                    <option value="@s.SiteId">@s.Name</option>
                }
            </select>
        }

        <LineChart @ref="lineChart" TItem="double" />

    </Authorized>
</AuthorizeView>

@code {
    // AuthenticationState is available as a CascadingParameter
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    SiteService _siteService;
    UensService _uensService;

    IEnumerable<Site> sites;
    IEnumerable<UensTransact> uensTrans;

    int iSiteId = 0;

    string[] labels = { };
    LineChart<double> lineChart;

    List<string> backgroundColors = new List<string> { ChartColor.FromRgba( 255, 99, 132, 0.2f ), ChartColor.FromRgba( 54, 162, 235, 0.2f ), ChartColor.FromRgba( 255, 206, 86, 0.2f ), ChartColor.FromRgba( 75, 192, 192, 0.2f ), ChartColor.FromRgba( 153, 102, 255, 0.2f ), ChartColor.FromRgba( 255, 159, 64, 0.2f ) };
    List<string> borderColors = new List<string> { ChartColor.FromRgba( 255, 99, 132, 1f ), ChartColor.FromRgba( 54, 162, 235, 1f ), ChartColor.FromRgba( 255, 206, 86, 1f ), ChartColor.FromRgba( 75, 192, 192, 1f ), ChartColor.FromRgba( 153, 102, 255, 1f ), ChartColor.FromRgba( 255, 159, 64, 1f ) };

    protected override async Task OnInitializedAsync()
    {
        // Get the current user (not currently used in this file)
        var user = (await authenticationStateTask).User;

        _siteService = (SiteService)ScopedServices.GetService(typeof(SiteService));
        _uensService = (UensService)ScopedServices.GetService(typeof(UensService));

        //get all sites
        sites = await _siteService.GetAllSitesAsync();

    }

    async Task GetSales(ChangeEventArgs e)
    {
        iSiteId = int.Parse(e.Value.ToString());

        //get the sitePrefix as that is what UENS uses
        string sSitePrefix = await _siteService.GetSitePrefix(iSiteId);

        uensTrans = await _uensService.GetSalesBySite(sSitePrefix);

        List<string> axis = new List<string>();
        List<double> data = new List<double>();

        foreach (UensTransact trans in uensTrans)
        {
            data.Add((double)trans.TenderedAmount);
            axis.Add(trans.Date);
        }

        LineChartDataset<double> ds = new LineChartDataset<double>
        {
            Label = "UENS Sales",
            Data = data,
            BackgroundColor = backgroundColors,
            BorderColor = borderColors,
            Fill = true,
            PointRadius = 3,
            BorderWidth = 1,
            PointBorderColor = Enumerable.Repeat( borderColors.First(), 6 ).ToList()
        };

        labels = axis.ToArray();

        //lineChart = new LineChart<float>();

        lineChart.Clear();
        lineChart.AddLabel(labels);
        lineChart.AddDataSet(ds);
        await lineChart.Update();
    }

}
stsrki commented 4 years ago

Try to initialize chart with empty data before you call GetSales(). I think that's the problem. You're setting it on select and before that, it's null so that's the reason for null reference exception.

jaimunday commented 4 years ago

Sorry, do you have an example? I have tried adding the below in:

    protected override async Task OnInitializedAsync()
    {

        LineChartDataset<float> dsEmpty = new LineChartDataset<float>();

        lineChart.AddDataSet(dsEmpty);

        ......

but get the same error.

i really appreciate your help on this as it has been driving me crazy

stsrki commented 4 years ago

That should be enough, but not sure. Please post the stack trace of the error.

jaimunday commented 4 years ago

Full stack trace:

blazor.server.js:15 [2020-02-12T01:52:45.151Z] Error: System.NullReferenceException: Object reference not set to an instance of an object. at OneHub.Pages.SiteFinancials.OnInitializedAsync() in C:\Users\jm\VS Projects\repos\ProductionReporting\Pages\SiteFinancials.razor:line 69 at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync() e.log @ blazor.server.js:15 C @ blazor.server.js:8 (anonymous) @ blazor.server.js:8 (anonymous) @ blazor.server.js:1 e.invokeClientMethod @ blazor.server.js:1 e.processIncomingData @ blazor.server.js:1 connection.onreceive @ blazor.server.js:1 i.onmessage @ blazor.server.js:1

stsrki commented 4 years ago

Hi, look at this #592 . I think you have the same problem. Basically you need to initialize chart in OnAfterRenderAsync instead of OnInitializedAsync. Please let me know if it helps.

jaimunday commented 4 years ago

Legend! So it was a combination of having to call a blank DS in OnAfterRenderAsync that fixed it.

really appreciate the assistance.

stsrki commented 4 years ago

Glad I could help 👍