Javascript is not my strongest part and absolutely not in combination of Blazor but have with Google and some AI get an eventlistener that run code on my Blazor application if browsersize change.
Now I need to do the same with some of my <div id="abc"> because I have components that need to set height / width in pixels.
My Blazorfile :
@inject DivSizeService dServer
.. html ..
@code {
..
protected override async Task OnInitializedAsync()
{
dService.OnDivSizeChanged += HandleDivSizeChanged;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await dService.StartListeningForDivSizeChanges("abc");
await UpdateDivSize();
}
}
private async void HandleDivSizeChanged(object sender, DivSizeChangedEventArgs e)
{
if (e.ElementId == "abc")
{
await UpdateDivSize();
}
}
async Task UpdateDivSize()
{
divSize = await dService.GetDivSize("abc");
Style = "Width: " + (divSize.Width - 50).ToString() + "px; Height: " +
(divSize.Height - 50).ToString() + "px;";
ChildComponent.Refresh // pseudocode
}
And my DivSizeService (updated StartListening...):
public class DivSizeService
{
private readonly IJSRuntime _js;
public event EventHandler<DivSizeChangedEventArgs> OnDivSizeChanged;
public DivSizeService(IJSRuntime js)
{
_js = js;
}
public async Task<DivSize> GetDivSize(string elementId)
{
return await _js.InvokeAsync<DivSize>("getElementDimensions", elementId);
//var dimensions = await _js.InvokeAsync<DivSize>("getDimensionsA");
//return new DivSize { Width = dimensions.Width, Height = dimensions.Height };
}
public async Task StartListeningForDivSizeChanges(string elementId)
{
await _js.InvokeVoidAsync("registerResizeListener", elementId, DotNetObjectReference.Create(this)); // updated
}
[JSInvokable]
public void HandleDivSizeChanged(string elementId, DivSize newSize)
{
OnDivSizeChanged?.Invoke(this, new DivSizeChangedEventArgs(elementId, newSize));
}
}
public class DivSizeChangedEventArgs : EventArgs
{
public string ElementId { get; }
public DivSize NewSize { get; }
public DivSizeChangedEventArgs(string elementId, DivSize newSize)
{
ElementId = elementId;
NewSize = newSize;
}
}
And my Javascript (updated window.registerResizeListener):
window.getElementDimensions = function (elementId) {
const element = document.getElementById(elementId);
return {
width: element ? element.offsetWidth : 0,
height: element ? element.offsetHeight : 0
};
window.registerResizeListener = (element, dotnetReference) => {
const observer = new ResizeObserver(entries => {
for (let entry of entries) {
const rect = entry.contentRect;
console.log(entry.contentRect);
const size = {
width: rect.width,
height: rect.height
};
dotnetReference.invokeMethodAsync('DivSizeService.HandleDivSizeChanged', element, size);
}
});
observer.observe(document.getElementById(element));
}
My window.getElementDimensions works, I try to run that when browsersize changed but my div won't update size before that event are finished so that makes me get the previos size of my div.
When I use this code above I got :
Exception thrown: 'Microsoft.JSInterop.JSException' in System.Private.CoreLib.dll Exception thrown: 'Microsoft.JSInterop.JSException' in System.Private.CoreLib.dll Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer: Warning: Unhandled exception rendering component: Failed to execute 'observe' on 'ResizeObserver': parameter 1 is not of type 'Element'. TypeError: Failed to execute 'observe' on 'ResizeObserver': parameter 1 is not of type 'Element'.
I know that I get element = "abc" in my window.registerResizeElement but I guess it's not the right way to do this? It crash on observer.observe(element);
Update 1:
With help I got so far that my javascript recognize changes to my div id = "abc", but now I got error : Uncaught Error Error: System.ArgumentException: The type 'DivSizeService' does not contain a public invokable method with [JSInvokableAttribute("DivSizeService.HandleDivSizeChanged")].
Update 2: Problem solved!
I'm passing dotNetReference to my javascript, then I don't need to referens that here :
dotnetReference.invokeMethodAsync('DivSizeService.HandleDivSizeChanged', element, size);
The correct solution should be :
dotnetReference.invokeMethodAsync('HandleDivSizeChanged', element, size);