-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Syntax for writing a dictionary of attributes onto an element #5071
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Edit: @rynowak hijacking this post SummaryWe want to have a feature for splatting arbitrary attributes into an element or component. This will look like: <div @attributes="myAttributes" another="something">...</div> Status/ItemsPreview 6 update: The compiler support (splat operator) didn't make it for VS16.2-preview2. So it's possible to use this feature from components written in C#. We'll add the language feature in preview 7.
SyntaxOther attributes would be allowed to appear before or after the splat: <div foo= "bar" @attributes="myAttributes" another="something">...</div> Multiple splats are allowed: <div foo= "bar" @attributes="myAttributes" another="something" @attributes="myOtherAttributes">...</div> Attributes and expressions will be evaluated from left to right (as they are today). SemanticsWe should define this feature in terms of an
If desired we can also make this work for arbitrary objects by mapping their properties into key-value pairs like we do in ASP.NET Core routing. As in other languages we should rely on ordering to determine precedence. I propose we follow what typescript does, and allow later attributes to take precedence. Examples: @{
var values = new Dictionary<string, string>()
{
{ "a", "123" },
{ "b", "456" },
}
}
<!-- results in <div b="456" a="ABC"></div> -->
<div @attributes=values a="ABC"></div>
<!-- results in <div a="123" b="456"></div> -->
<div a="ABC" @attributes=values></div> Implementation concernsWe have a choice of how to implement this semantic. Given the following code: <div a="ABC" @attributes=values></div> This will map to something like: builder.OpenElement(0, "div");
builder.AddAttribute(1, "a" "ABC");
builder.AddMultipleAttributes(2, values);
builder.CloseElement(0, "div"); note: I propose that we do the obvious thing with sequence numbers... We map a single splat to a single render tree builder call and a single sequence number We have to decide how to do the de-duplication of the duplicate attribute (in this case I'm looking for thoughts and input on which is the better approach. |
@SteveSandersonMS - added some design notes, would like your feedback on this. |
This basically all looks great to me and matches what I think we've discussed before.
One further syntactic possibility is to copy JS/TS and be explicit that we're merging contents by prefixing with
You'd then get a compile error if you just tried to put I'm not 100% determined that we should do this, but am interested in what you think. |
I'm not sure JS-esque |
I don't think a feature is needed for this. If a component defines a |
Also, to your examples you could do exactly what you're asking for once we have the language feature by returning an |
Thanks, Yes, for some of the examples that are only providing another API in a typed manner then one would only need to handle duplicates (at most) and it resembles with this splat handling. For the list example I was hoping that one could have it generating other presets to child list-items to set 'list-group-item' automatically, and similar for the 'form' example, it could target settings of label, placeholder etc. To override the default render behaviour would mainly be to make those settings available to children. Making a component is always always an alternative but there is a risk of getting myriads of things like MyMaterialDesignForm, MyBootstrapForm, etc. When it is only about passing along settings to chidren it could be an alternative to have the ability of passing along defaults selectively to children (by target element ID or by type in these examples) instead of making a component for handling it. Can that be done somehow with CaptureUnmatchedAttributes? To be used by child elements selectively instead of making components? |
For now this kind of scheme would have to be built-in the the component you're calling. We have no immediate plans (3.0) to build metaprogramming or macro-like extensbility. |
Yes, a macro might behave similarly but then the elements need to be predefined. Building on this splat feature, please note that you should already be able to achieve this by having one "splat factory" register values to a service that another "splat factory" retrieves values from in a child element giving some filter key. Manually injecting those factory calls on all child elements would be impractical and ugly though. I wanted to point out the similarities to see if those calls could be handled somehow by the framework instead. Anyway, thanks for thinking about it. |
@rynowak Did this issue stall on us not concluding the syntax/name? Or do you consider the plan to be decided? |
Correct. I'm proposing we use |
Even for components, even ones that might not have anything to do with HTML rendering? I feel a bit odd about this, but maybe we justify it by saying you're meant to think of it as a syntactical macro - you're asking the framework to pretend a bag of stuff was actually a bunch of attributes in your anglebrackets-source-code. It is strange though: <PersonEditor Person="@data.Person" @attributes=@ExtraParams />
@functions {
[Parameter(CaptureExtraValues = true)] public IDictionary<string, object> ExtraParams { get; set; }
} |
I really don't want to pick a different name for applying extra attributes to components. That sounds like something we'll explain to users eternally. |
Yep, having two names would be pretty sucky and I don't want that either. But the problems with |
I think I also like |
Who didn't agree. Cool people or .... them? |
OK. Philosophically, In the end none of the other options are ideal either, so I'll stop being perfectionist about this. I can accept |
In a mixed environment of C# and HTML I think it is a bit unfortunate to use the name attributes. Isn't something like |
Why not use this syntax to avoid conflicting with the directive attributes
I don't think it gets clearer than that IMO. |
@stavroskasidis we considered this and we don't want to make a distinction in behavior between two constructs that are very similar in other contexts. Ex:
In examples 1 and 2 they are semantically equivalent (evaluate the expression). In examples 3 and 4 they are different. 3 is a directive attribute, and 4 is an expression. When you but these examples side-by-side it starts to get vexing. We don't expect the usage of this feature to be extremely common, and using an attribute for it is already pretty concise. We have the ability to make something more concise later if it's needed. |
Ok, that makes sense. Thank you for answering. |
In preview6 |
@abhisheksiddhu Applying an attribute to a component class is actually done with |
This issue is being opened by request of @SteveSandersonMS Please see the full issue details https://github.com/aspnet/Blazor/issues/735 in the Blazor Repo.
The summary is that will be nice to be able to pass arbitrary attributes from a custom component down to an HTML element. For example:
<MyComponent id="myid" />
in the component render it as:
<button id="myid" />
without having to code every single attribute possible. Not mention allowing attributes such data-* to be passed down.
The text was updated successfully, but these errors were encountered: