I have a javascript event I need to listen for (kicked off by an outside vendor library) and then act on that inside of my component by hiding some content when that event is fired. I've gotten it working when the component only appears on a given page once, but the first instance of the component doesn't work when the component is included on the page more than once.
The component code:
...
// this is a method that is called internally by the component when needed but also externally
// when the javascript event is fired by the 3rd party library that controls an input box on
// the screen that has an "x" icon in it that clears out its contents. This code also clears
// out the resulting list of data that came back when the user typed something into it
[JSInvokable("CancelAutocomplete")]
public async Task CancelAutocomplete()
{
this.IsLoading = false;
this.SearchResults = null;
await InvokeAsync(StateHasChanged);
}
// this i found online to combat the need for a static method when invoking blazor code from js
// see the next code block down to see what this looks like on the JS side
private DotNetObjectReference<PersonAutocompleteInput>? dotNetHelper;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
dotNetHelper = DotNetObjectReference.Create(this);
await JS.InvokeVoidAsync("Helpers.setDotNetHelper", dotNetHelper);
}
}
/// <summary>
/// Disposes of the dotNetHelper so its not gobbling memory
/// </summary>
protected override void Dispose(bool disposed)
{
base.Dispose(disposed);
this.dotNetHelper?.Dispose();
}
Then there is the javascript code (currently called from my MainLayout.razor.js so it would be available on any page that might use the above component):
...
class Helpers {
static dotNetHelper;
static setDotNetHelper(value) {
Helpers.dotNetHelper = value;
}
static async cancelAutocomplete() {
await Helpers.dotNetHelper.invokeMethodAsync('CancelAutocomplete');
}
}
window.Helpers = Helpers;
In the same javascript file is the code that actually listens for the custom javascript event:
// our 3rd party library throws the 'custom-clear-click' event when a user presses the 'x' icon in a user input box to clear the text
// when that happens we should clear out the autocomplete box as well
document.addEventListener('custom-clear-click', (evt) => {
Helpers.cancelAutocomplete();
});
In the razor component itself there is code that shows or hides based on whether there are results in SearchResults:
@if (this.SearchResults != null)
{
... html stuff here
}
To summarize, this all works when the component only appears once, however if it appears twice on the page nothing happens for the first component, it only works on the second component. No errors thrown in the console.
After some discussion here and further research here
My final solution works and looks like this:
MainLayout.razor.js
Component .razor code
Component .razor html