Closed chanan closed 5 years ago
Mate, ElementRef is an opaque reference object holding a reference to an Html element, but it cannot be used in C#. You use it only when you want to pass a reference to an Html element to JavaScript only. The parameter accepted in a JavaScript object, such as a function, behaves just as if it was an object reference retrieved, say, by getElementById()
Yes. I didn’t paste the JavaScript I used but it was a console log. It should be able to print the element ref. So if I was using a input I would expect elementRef.value to work for example.
@chanan, you can read about the ElementRef here: https://blazor.net/docs/javascript-interop.html
Thanks, but I know how to use the elementRef. I am trying to expose the html elementRef from my component (code above) to the user of my component so that they can use it themselves. The problem is as I pointed out in the javascript console (shown above) it gets to javascript "empty" (again see log)
@chanan,
Once again, the ElementRef is not intended to be used in your C# code. It can and should only be passed to a JavaScript function. Now, if you want to pass an ElementRef to the user of your component, I don't see anything that could stop you from doing it. Just define a property of type ElementRef with get and set accessors, and pass it to whomever you want. But again, the receiver of that reference (meaning element reference) can do nothing with it, such as accessing the properties of the element. The only thing the receiver of your element reference can do is pass it to a JavaScript function...
Yes, i am aware of that and that is what I am doing. The output I showed on my bug is from a console.log in JavaScript.
Because it seems like it was causing some confusion, I updated the bug ticket with the exact javascript code I am using.
This is the the value that is marshalled to javascript, if the ElementRef
on the C# side does not point to a valid html element. I came accross the same issue when writing a library where a non-present html reference was a valid case and I wanted to handle this case directly in JS. My solution to this is (in JS, adapted to your case):
window.alertValue= function(element) {
if(!element || element._blazorElementRef === null) {
// There was no html element reference passed. Handle this case accordingly.
console.log("No element ref captured.");
}
else {
console.log("element: %O", element);
}
}
I think in your case, you have to use two way binding of the ElementRef
property of your component. The inputRef
variable of your outer component is never updated, when the Dynamic
component updates its ElementRef
property.
@AndreasTruetschel Yes, I think that is what is happening. I am not sure how to fix it though.
I thought you might have meant changing the outer component to:
<Dynamic TagName="input" ElementRef="@inputRef" />
but that throws an error:
ncaught (in promise) Error: System.ArgumentException: 'bind' does not accept values of type Microsoft.AspNetCore.Blazor.ElementRef. To read and write this value type, wrap it in a property of type string with suitable getters and setters.
at Microsoft.AspNetCore.Blazor.Components.BindMethods.SetValueHandler[T]
I cannot follow how the exception is thrown exactly, but for binding to work, you habe to specify the binding in the component that uses your Dynamic
component, like
<Dynamic TagName="input" bind-ElementRef="inputRef" />
You don't need the @
here but have to specifiy the bind-
.
And in the Dynamic
component you need a Parameter that takes an Action<ElementRef>
called ElementRefChanged
. Then you can invoke the delegate each time the element changes and Blazor will insert an action for the binding appropriately.
This has to look like (in the Dynamic Component):
[Parameter] private ElementRef ElementRef {get;set;}
[Parameter] private Action<ElementRef> ElementRefChanged {get;set;}
and in your BuildRenderTree
method:
builder.AddElementReferenceCapture(2, capturedRef =>
{
ElementRef = capturedRef;
ElementRefChanged?.Invoke(ElementRef); // Invoke the callback for the binding to work.
});
This is really nothing special and works for any type and not only strings. It is described here (See the Component parameters subsection)
@AndreasTruetschel is correct. You will need bind-something
for this to work, otherwise this line of code:
builder.AddElementReferenceCapture(2, capturedRef => { ElementRef = capturedRef; });
... is only writing to its own ElementRef
property, not to the corresponding property on the caller.
Since you're writing your component in raw C# instead of Razor, you'll have to figure out what C# code is equivalent to the bind-something
that Razor would generate.
I believe this should be added to the official Input[*] components that are meant to be used with EditForm. I recently wanted to build a word processor for a complicated form and took me a whole day to find and form a working solution
I have a component that inherits from BlazorComponent with this code:
It's used like so:
Which ultimately prints out to the console what the ref is. Like so:
One the javascript console I get: