LayTec-AG / Plotly.Blazor

This library packages the well-known charting library plotly.js into a razor component that can be used in a Blazor project.
MIT License
351 stars 51 forks source link

Cannot read properties of undefined (reading 'newPlot') #166

Closed CliffBDev closed 1 year ago

CliffBDev commented 2 years ago

Getting the following error when trying to implement an example from the examples section of the project. crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Cannot read properties of undefined (reading 'newPlot') TypeError: Cannot read properties of undefined (reading 'newPlot') at Object.newPlot (http://localhost:5054/_content/Plotly.Blazor/plotly-interop.js:3:23) at http://localhost:5054/_framework/blazor.webassembly.js:1:3332 at new Promise () at Object.beginInvokeJSFromDotNet (http://localhost:5054/_framework/blazor.webassembly.js:1:3306) at Object.St [as invokeJSFromDotNet] (http://localhost:5054/_framework/blazor.webassembly.js:1:59849) at _mono_wasm_invoke_js_blazor (http://localhost:5054/_framework/dotnet.6.0.4.dckq00jdfr.js:1:195300) at http://localhost:5054/_framework/dotnet.wasm:wasm-function[219]:0x1a0fb at http://localhost:5054/_framework/dotnet.wasm:wasm-function[167]:0xcac9 at http://localhost:5054/_framework/dotnet.wasm:wasm-function[166]:0xb9dc at http://localhost:5054/_framework/dotnet.wasm:wasm-function[2810]:0xabb22 Microsoft.JSInterop.JSException: Cannot read properties of undefined (reading 'newPlot') TypeError: Cannot read properties of undefined (reading 'newPlot') at Object.newPlot (http://localhost:5054/_content/Plotly.Blazor/plotly-interop.js:3:23) at http://localhost:5054/_framework/blazor.webassembly.js:1:3332 at new Promise () at Object.beginInvokeJSFromDotNet (http://localhost:5054/_framework/blazor.webassembly.js:1:3306) at Object.St [as invokeJSFromDotNet] (http://localhost:5054/_framework/blazor.webassembly.js:1:59849) at _mono_wasm_invoke_js_blazor (http://localhost:5054/_framework/dotnet.6.0.4.dckq00jdfr.js:1:195300) at http://localhost:5054/_framework/dotnet.wasm:wasm-function[219]:0x1a0fb at http://localhost:5054/_framework/dotnet.wasm:wasm-function[167]:0xcac9 at http://localhost:5054/_framework/dotnet.wasm:wasm-function[166]:0xb9dc at http://localhost:5054/_framework/dotnet.wasm:wasm-function[2810]:0xabb22 at Microsoft.JSInterop.JSRuntime.d__161[[Microsoft.JSInterop.Infrastructure.IJSVoidResult, Microsoft.JSInterop, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].MoveNext() at Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(IJSRuntime jsRuntime, String identifier, Object[] args) at Plotly.Blazor.PlotlyJsInterop.NewPlot(IJSRuntime jsRuntime, DotNetObjectReference1 objectReference) at Plotly.Blazor.PlotlyChart.NewPlot() at Plotly.Blazor.PlotlyChart.OnAfterRenderAsync(Boolean firstRender) at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

My razor component: `@using Plotly.Blazor.LayoutLib

PlotlyTestComponent

<PlotlyChart Id="TestId" Config="config" Layout="layout" Data="data" @ref="chart"/>

@code { PlotlyChart chart;

Config config = new Config
{
    Responsive = true
};

Layout layout = new Layout
{
    Title = new Title
    {
        Text = "Bar"
    },
    BarMode = BarModeEnum.Stack,
    Height = 500
};

List<ITrace> data = new List<ITrace>
{
    new Bar
    {
        X = new List<object> {"giraffes", "orangutans", "monkeys"},
        Y = new List<object> {20, 14, 23},
        Name = "SF Zoo"
    },
    new Bar
    {
        X = new List<object> {"giraffes", "orangutans", "monkeys"},
        Y = new List<object> {12, 18, 29},
        Name = "LA Zoo"
    }
};

}`

_Imports.razor: ... @using Plotly.Blazor; @using Plotly.Blazor.Traces;

index.html: `

<!-- Import the plotly.js interop functions -->
<script src="_content/Plotly.Blazor/plotly-interop.js" type="text/javascript"></script>`
DarkEyeDragon commented 2 years ago

My first guess is that the chart isn't initialized yet. If you want to initialize it with data you'll have to do it on OnAfterRenderAsync and check the "firstRender" bool.

Annother possibility:

JS#InvokeAsync parses your objects to json. Properties you don't define get defaulted to null. While the default behavior of Plotly is to just not define things you don't pass. So no null checks are done. Currently there is no way to change the default behavior of the json parser. So you'll have to strip the null values in JS.

You can do that with something like:

function clean(obj) {
    for (let propName in obj) {
        if (obj[propName] === null || obj[propName] === undefined) {
            delete obj[propName];
        }
    }
    return obj
}

Do note that this is not recursive (so sub properties that are objects are not looped over) An example: of its usage: opts.series[1] = clean(opts.series[1])