3

I need, in Blazor, get a reference to a component by its ID. Note: Not using ElementReference, as it is for generic code.

I've used this JS Interop script to do a focus and it works fine for me:

public async Task Focus(string elementId){
        await js.InvokeVoidAsync("eval", $@"document.getElementById(""elementId}"").focus()");
}

But what I need from Blazor is get only a reference to the element (the component), that is, the return of: document.getElementById(""{elementId}"") sending it elementId as a parameter.

Is it possible?

Edit: I've tried with this script but always returns null when calling it from Blazor:

<script>
        window.GetElementById = (myId) => {
            return document.getElementById(myId);
        }
</script>
KlemenPl
  • 354
  • 4
  • 21
Antonito
  • 77
  • 1
  • 9

1 Answers1

4

Update

To specifically answer your question.

You're calling with InvokeVoidAsync which returns a void as you see. If you call with InvokeAsync you get an empty JsonDocument object returned.

So no, you can't get a usable reference back from the js call.

Previous Answer before clarification of question

============================================================ If I read your question correctly, you want to set the focus to an html element id that you're generating "generically".

The answer below shows how to set the focus using either Element or id.

Add a site.js to wwwroot with the following code:

window.SetElementFocus = function (element) {
    element.focus();
    return element === true;
}

window.SetFocusByElementId = function (elementId) {
    var element = document.getElementById(elementId);
    element.focus();
    return element === true;
}

Reference the js file in your startup file (this is for server)

    <script src="/site.js"></script>
    <script src="_framework/blazor.server.js"></script>

And then here's a demo page.

@page "/Test6"
<div class="m-2">
    <input type="text" @ref="Input1" placeholder="Input 1" id="input1" />
</div>

<div class="m-2">
    <input type="text" @ref="Input2" placeholder="Input 2" id="input2" />
</div>

<div class="m-2">
    <input type="text" @ref="Input3" placeholder="Input 3" id="input3" />
</div>

<div class="m-2 p-2">
    <button class="btn btn-dark me-1" @onclick="() => Focus(1)">Element Focus 1</button>
    <button class="btn btn-dark me-1" @onclick="() => Focus(2)">Element Focus 2</button>
    <button class="btn btn-dark me-1" @onclick="() => Focus(3)">Element Focus 3</button>
</div>

<div class="m-2 p-2">
    <button class="btn btn-secondary me-1" @onclick="() => FocusById(1)">Id Focus 1</button>
    <button class="btn btn-secondary me-1" @onclick="() => FocusById(2)">Id Focus 2</button>
    <button class="btn btn-secondary me-1" @onclick="() => FocusById(3)">Id Focus 3</button>
</div>


@code {

    [Inject] private IJSRuntime _js { get; set; }

    private ElementReference Input1;
    private ElementReference Input2;
    private ElementReference Input3;

    private async Task Focus(int no)
    {
        var input = no switch
        {
            1 => Input1,
            2 => Input2,
            _ => Input3
        };
        await _js.InvokeAsync<bool>("SetElementFocus", input);
    }

    private async Task FocusById(int no)
    {
        var input = no switch
        {
            1 => "input1",
            2 => "input2",
            _ => "input3"
        };
        await _js.InvokeAsync<bool>("SetFocusByElementId", input);
    }
}
MrC aka Shaun Curtis
  • 19,075
  • 3
  • 13
  • 31
  • Not really focusing, because it already works well for me. What I want is just getting in Blazor the element, i. e. the return of this JS expression: document.getElementById("myId"), without focusing the element; sending the myId as a parameter from Blazor. – Antonito Jul 28 '21 at 13:47
  • What type of "object" are you expecting to get back and what do you want to do with it? You're calling it with `InvokeVoidAsync` which returns a void. Calling it with `InvokeAsync` gets you a JsonDocument object that contains nothing. – MrC aka Shaun Curtis Jul 28 '21 at 15:13
  • Just expecting return an object .net type. The InvokeVoidAsync was just as a working focusing example, but what I need is return the element, with a script like the one I added at the end, but it returns null. – Antonito Jul 28 '21 at 15:55
  • Whatever you were planning to do with the returned object, you need to rethink your design. What do you want it for? – MrC aka Shaun Curtis Jul 28 '21 at 21:33
  • I really have very little knowledge of JavaScript, so I ask. If there is no other option, then I would look for another solution. I really appreciate your help but my question is specifically if that is possible. From your answer I must assume that no. – Antonito Jul 28 '21 at 23:24
  • @Antonito, from what I understand, you want to manipulate an element like you do in javascript from blazor? – Cool Developer Jul 29 '21 at 08:00
  • @Antonito - I've updated the answer with No you can't get anything back. Time for a rethink! – MrC aka Shaun Curtis Jul 29 '21 at 16:52