Unhandled Null Exception
Issue: I'm encountering an unhandled null exception using this library.
The exception occurs randomly.
Cannot read properties of null (reading 'assignedSlot') TypeError: Cannot read properties of null (reading 'assignedSlot') at b (https://unpkg.com/@popperjs/core@2:5:2514) at x (https://unpkg.com/@popperjs/core@2:5:2668) at w (https://unpkg.com/@popperjs/core@2:5:2721) at Object.setOptions (https://unpkg.com/@popperjs/core@2:5:8209) at Module.setOptionsOnInstance (https://localhost:4343/_content/KristofferStrube.Blazor.Popper/KristofferStrube.Blazor.popper.js:43:21)
at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args) at KristofferStrube.Blazor.Popper.Instance.SetOptions(Options options) at KristofferStrube.Blazor.Popper.TogglePopperComponent.OpdatePopperAsync() at KristofferStrube.Blazor.Popper.TogglePopperComponent.PointerMove() at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task) at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState) An unhandled error has occurred. Usually an invalid page request.
Configuration: Visual Studio 2022 Version 17.11.4 Blazor Server-Side application .Net 8
dotnet --info .NET SDK: Version: 8.0.401 Commit: 811edcc344 Workload version: 8.0.400-manifests.251308be MSBuild version: 17.11.4+37eb419ad
Runtime Environment: OS Name: Windows OS Version: 10.0.22631 OS Platform: Windows RID: win-x64 Base Path: C:\Program Files\dotnet\sdk\8.0.401\
.NET workloads installed: Configured to use loose manifests when installing new manifests. [android] Installation Source: VS 17.11.35312.102 Manifest Version: 34.0.113/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.android\34.0.113\WorkloadManifest.json Install Type: FileBased
[maui-windows] Installation Source: VS 17.11.35312.102 Manifest Version: 8.0.82/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maui\8.0.82\WorkloadManifest.json Install Type: FileBased
[maccatalyst] Installation Source: VS 17.11.35312.102 Manifest Version: 17.5.8030/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maccatalyst\17.5.8030\WorkloadManifest.json Install Type: FileBased
[ios] Installation Source: VS 17.11.35312.102 Manifest Version: 17.5.8030/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.ios\17.5.8030\WorkloadManifest.json Install Type: FileBased
[wasm-tools-net6] Installation Source: VS 17.11.35312.102 Manifest Version: 8.0.8/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.workload.mono.toolchain.net6\8.0.8\WorkloadManifest.json Install Type: FileBased
[wasm-tools-net7] Installation Source: VS 17.11.35312.102 Manifest Version: 8.0.8/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.workload.mono.toolchain.net7\8.0.8\WorkloadManifest.json Install Type: FileBased
[wasm-tools] Installation Source: VS 17.11.35312.102 Manifest Version: 8.0.8/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.workload.mono.toolchain.current\8.0.8\WorkloadManifest.json Install Type: FileBased
[aspire] Installation Source: VS 17.11.35312.102 Manifest Version: 8.1.0/8.0.100 Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.aspire\8.1.0\WorkloadManifest.json Install Type: FileBased
Host: Version: 8.0.8 Architecture: x64 Commit: 08338fcaa5
.NET SDKs installed: 8.0.400 [C:\Program Files\dotnet\sdk] 8.0.401 [C:\Program Files\dotnet\sdk]
.NET runtimes installed: Microsoft.AspNetCore.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Other architectures found: x86 [C:\Program Files (x86)\dotnet] registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]
Environment variables: Not set
global.json file: Not found
Modifying target framework to .NET 8 & upgrading all packages from 6.x.x to 8.x.x reduced the null exceptions.
However, I think there is a missing parent relationship between the arrow and the popper element.
Hey @HowardFedTec I think you are right in it probably being caused by a mismatch in what versions of the component libraries and .NET version you were using. I have had the idea of making the dependencies differ depending on the target .NET version. This points to that idea as something that should be prioritized by me.
With regards to the other part with the arrow then you might be missing some of the CSS that styles the arrow in my sample app: https://github.com/KristofferStrube/Blazor.Popper/blob/main/samples/KristofferStrube.Blazor.Popper.Samples/wwwroot/css/app.css#L205-L239
Hi.
Thank you for responding.
I forked your project. There are a couple of issues I found.
- The .Net versions caused some issues. The Microsoft Components package seems to be the primary culprit. After upgrading the projects to .Net 8 and all the packages to the latest version. That helped, but I still received different errors.
- If the user is in the start of or middle of navigation and they mouseover a popper, it throws an exception because the DOM element is already destroyed. I fixed that with a couple of try catches.
- I did pull in your css, but the arrow still throws an exception also. I've set AddArrow="false" at the moment and am not using arrows and I have no issue. I have no fix for the arrow exception. I will double check and make sure I captured all the required css.
I can send you my code changes for #2 if you'd like me to. It's a simple fix.
Howard
Is point 2 specifically for the TogglePopperComponent?
Change 1:
Problem: The popper reference is null. Possibly becuase dom hasn't created it yet, so no options can be set.
Fix: Catch and ignore the exception. It will be recreated on the next mouse action, or so it appears.
File: popper.js
export async function setOptionsOnInstance(instance, options) {
await cleanOptions(options);
try {
return instance.setOptions(options).then(state => stripState(state));
}
catch (e) {
//console.error(e);
}
}
Change 2:
Problem: Upon navigating away from the page, the object reference(s) may not exist depending on the state of the DOM.
Fix: Catch and ignore the exception. The instance will be recreated on the next action and exists. Created instance variables at the top of the method. Return instance when successful. Return null when exception encountered.
File: Popper.cs
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System;
using System.Threading.Tasks;
namespace USMC.TECOM.Blazor.Popper;
public class Popper
{
private readonly IJSRuntime jSRuntime;
public Popper(IJSRuntime jSRuntime)
{
this.jSRuntime = jSRuntime;
}
public async Task<Instance> CreatePopperAsync(ElementReference reference, ElementReference popper, Options options)
{
IJSObjectReference jSInstance=null;
if (jSRuntime is IJSInProcessRuntime)
{
try
{
IJSInProcessObjectReference popperWrapper = await jSRuntime.InvokeAsync<IJSInProcessObjectReference>("import", "./_content/USMC.TECOM.Blazor.Popper/USMC.TECOM.Blazor.popper.js");
jSInstance = await popperWrapper.InvokeAsync<IJSObjectReference>("createPopper", reference, popper, options);
#pragma warning disable CS0618 // Type or member is obsolete
return new(jSInstance, popperWrapper);
#pragma warning restore CS0618 // Type or member is obsolete
}
catch (Exception ex)
{
//Console.WriteLine(ex.Message);
}
}
else
{
try
{
IJSObjectReference popperWrapper = await jSRuntime.InvokeAsync<IJSObjectReference>("import", "./_content/USMC.TECOM.Blazor.Popper/USMC.TECOM.Blazor.popper.js");
jSInstance = await popperWrapper.InvokeAsync<IJSObjectReference>("createPopperAsync", reference, popper, options);
return new(jSInstance, popperWrapper);
}
catch (Exception ex)
{
// This is the main problem exception when the instance cannot be created.
// Console.WriteLine(ex.Message);
}
}
return null;
}
public async Task<Instance> CreatePopperAsync(VirtualElement reference, ElementReference popper, Options options)
{
IJSObjectReference jSInstance = null;
if (jSRuntime is IJSInProcessRuntime)
{
try
{
IJSInProcessObjectReference popperWrapper = await jSRuntime.InvokeAsync<IJSInProcessObjectReference>("import", "./_content/USMC.TECOM.Blazor.Popper/USMC.TECOM.Blazor.popper.js");
jSInstance = await popperWrapper.InvokeAsync<IJSObjectReference>("createPopper", reference, popper, options);
#pragma warning disable CS0618 // Type or member is obsolete
return new(jSInstance, popperWrapper);
#pragma warning restore CS0618 // Type or member is obsolete
}
catch (Exception ex)
{
//Console.WriteLine(ex.Message);
}
}
else
{
try
{
IJSObjectReference popperWrapper = await jSRuntime.InvokeAsync<IJSObjectReference>("import", "./_content/USMC.TECOM.Blazor.Popper/USMC.TECOM.Blazor.popper.js");
jSInstance = await popperWrapper.InvokeAsync<IJSObjectReference>("createPopperAsync", reference, popper, options);
return new(jSInstance, popperWrapper);
}
catch (Exception ex)
{
//Console.WriteLine(ex.Message);
}
}
return null;
}
}
I haven't seen it fail like that before. If you could supply a minimal sample that I could clone to get the error myself then I would love to see if there is something more fundamental I could fix instead of treating the symptom.
I'd be happy to. No guarantee on my timing though. I'm preparing for a customer demonstration for one of my projects this week.
No rush. I'm also pretty tied up this week preparing for a talk. 😊
Hi. I found an object not being disposed in VirtualElement. Here is my suggested change.
#nullable enable
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System;
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
namespace USMC.TECOM.Blazor.Popper;
public class VirtualElement : IDisposable
{
[Required]
public DotNetObjectReference<VirtualElement>? objRef { get; set; } = null;
public VirtualElement()
{
objRef = DotNetObjectReference.Create(this);
ArgumentNullException.ThrowIfNull(objRef);
}
[JsonIgnore]
public Func<ClientRect> GetBoundingClientRect { get; set; }
[JSInvokable("CallGetBoundingClientRect")]
public ClientRect CallGetBoundingClientRect() => GetBoundingClientRect.Invoke();
[JsonPropertyName("contextElement")]
public ElementReference ContextElement { get; set; }
//HGS: Modified 2/4/2025 to clean up the object.
public void Dispose()
{
if (objRef != null)
{
objRef?.Dispose();
objRef = null;
}
}
}
Hey @HowardFedTec really good catch. :) Would you like to contribute this through a PR? :)
@KristofferStrube , Sure. I'll get it done shortly. Thx!