Почему мой компонент blazor с ElementReference и IJSRuntime.InvokeAsync внутри цикла for не работает
В разметке компонента blazor (сервера) я пытаюсь вызвать функцию javascript для каждого элемента, добавленного внутри цикла. Это сложно объяснить... надеюсь, этот фрагмент кода поможет:
@page "/"
@inject IJSRuntime JS
@for(var i = 0; i < 3; i++)
{
ElementReference div;
<div @ref="div">this should get replaced....</div>
JS.InvokeVoidAsync("Test", div, i); @* where Test is defined as: function Test(el, i) { el.innerHTML = i; }*@
}
Если я поступаю неправильно... каков правильный путь?
Для большего контекста вот что я на самом деле пытаюсь сделать:
@page "/"
@inject IJSRuntime JS
@foreach(var data in jsonItems)
{
ElementReference div;
<div @ref="div"></div>
JS.InvokeVoidAsync("JsonView.renderJSON", data, div); @* https://github.com/pgrabovets/json-view *@
}
@code
{
private readonly IEnumerable<string> jsonItems = new List<string> {"{}", "{}"};
}
Я создал эту скрипку Blazor, если это поможет... https://blazorfiddle.com/s/428ov3ku
1 ответ
Решение
Вы не можете использовать объект ElementReference, пока ему не была назначена ссылка на элемент. Ваш компонент еще не создан и не отрисован, поэтому объект ElementReference недоступен. Вы можете использовать объекты ElementReference только после того, как ваш компонент был отрисован.
Сделать это можно так:
@inject IJSRuntime JSRuntime
@foreach (var div in divs)
{
<div @ref="div.ElementReference"></div>
}
@code
{
private readonly IEnumerable<Div> divs = new List<Div> { new Div{JSON="{1}" },
new Div{JSON="{2}"},
new Div{JSON="{3}"}};
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
@foreach (var div in divs)
{
await JSRuntime.InvokeVoidAsync(
"exampleJsFunctions.jsonRenderer", div.JSON, div.ElementReference);
}
}
}
public class Div
{
public ElementReference ElementReference { get; set; }
public string JSON { get; set; }
}
}
Поместите скрипт в конец вашего файла _Host.cshtml...
<script>
window.exampleJsFunctions = {
jsonRenderer: function (json, element) {
element.innerText = json;
}
}
</script>