Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using @ref inside for loop to get element reference

Im trying to get the position of same object in different places, where ,with a javascript function, I should get different top positions but thats not the scenario. The script code:

<script type="text/javascript">
    window.ShowAlert = function myFunction(element) {   
    console.log("Hello World.");
    alert(element.offsetTop);
   }
</script>

The Index.razor code:

@inject IJSRuntime jsRuntime

<div>
    @for (int i = 0; i < 10; i++)
    {
        <div @onclick="MemberFunction" @ref="memberRef">Click Here</div>
    }

</div>

@code {

    private ElementReference memberRef;
    void MemberFunction()
    {
        jsRuntime.InvokeAsync<object>("ShowAlert", memberRef);
    }
}

As you can see here Im doing a for in the same div, where he goes down the line. What I want from this is for every div posted it should give me a different value of offsetTop, because he goes down the line one by one. How can I manage this problem?

For a better understanding here you have a demo https://blazorfiddle.com/s/4g57o82k . As you can see in the demo the value for each Click Here is the same.

Thank you for your attention.

like image 583
LOL Jovem Avatar asked Oct 02 '19 15:10

LOL Jovem


1 Answers

Edit:

I believe that this is a bug, so I created an issue. If it's not an issue or it get fixed, I will update here.

Looking at the docs about lambda expressions

Do not use the loop variable (i) in a for loop directly in a lambda expression. Otherwise the same variable is used by all lambda expressions causing i's value to be the same in all lambdas. Always capture its value in a local variable (buttonNumber in the preceding example) and then use it.

So looking at the issue and the answer it was given I tweak it a little and manage to make it work.

You need to define a new varible inside the for to hold the value of i.

@inject IJSRuntime jsRuntime

<div>
    @for(var i = 0; i < memberRef.Count(); i++)
    {
        var i2 = i;
        <div @onclick="() => MemberFunction(i2)" @ref="memberRef[i2]">Click Here</div>
    }
</div>

@code {

    private ElementReference[] memberRef { get; set; } = new ElementReference[11];
    void MemberFunction(int i)
    {
        jsRuntime.InvokeAsync<object>("ShowAlert", memberRef[i]);
    }

}

Here is a working fiddle.

like image 52
Vencovsky Avatar answered Nov 15 '22 13:11

Vencovsky