Skip to content
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

Add ability to pass @typeparam down to child components #7268

Closed
ivanchev opened this issue Feb 5, 2019 · 12 comments
Closed

Add ability to pass @typeparam down to child components #7268

ivanchev opened this issue Feb 5, 2019 · 12 comments
Assignees
Labels
affected-few This issue impacts only small number of customers area-blazor Includes: Blazor, Razor Components component ecosystem Indicates an issue which also has impact on 3rd party component ecosystem Components Big Rock This issue tracks a big effort which can span multiple issues enhancement This issue represents an ask for new feature or an enhancement to an existing one Needs: Design This issue requires design work before implementating. severity-blocking This label is used by an internal tool

Comments

@ivanchev
Copy link

ivanchev commented Feb 5, 2019

Is your feature request related to a problem? Please describe.

If you have a templated component, that's Generic and uses @typeparam, if you want to add other child components, you also have to specify the type when you declare them. For instance in a Grid:

<Grid Data=List<Item>>
  <Columns>
    <Column TItem=Item>
      <Template />
    </Column>
  </Columns>
</Grid>

In this setup, in order to have a strongly typed context passed to the Column templates, you have to specify explicitly TItem to each Column and cannot be inferred by the List.

Describe the solution you'd like

With the current setup we can pass simple parameters down to child components with:

<CascadingValue Value=this>
    @Columns
</CascadingValue>

I would like to have the ability to aslo pass down @typeparam values. Perhaps something like:

<CascadingType Value=TItem>
    @Columns
</CascadingType>

And if the child component declares it's own TItem, it will override the Cascading value.

@muratg muratg added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Feb 5, 2019
@danroth27 danroth27 added area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one Needs: Design This issue requires design work before implementating. labels Feb 6, 2019
@danroth27 danroth27 added this to the 3.0.0-preview4 milestone Feb 9, 2019
@SteveSandersonMS
Copy link
Member

I agree with the needs-design label!

It's not clear to me what the right design for this would be, or even if it's possible at all. If the outer component obtained its generic type through inference, then the generated code doesn't know about it at all prior to compilation. So I'm not clear that it's possible to pass it to nested components.

@rynowak Am I missing any obvious possible solution? Do you have any ideas about how something like this could be achieved? Or if not, any thoughts on an alternative feature we might be able to offer to achieve a similar goal of determining generic types based on tag hierarchy? Better still would be inferring generic types based on cascading parameters, but I don't see how that would be possible given that we don't know about cascading parameters until runtime.

@ivanchev
Copy link
Author

If inference is the main problem, having to specify the type on the main component explicitly is still a viable option, as long as it's only specified in just one place.

@rynowak rynowak added the Components Big Rock This issue tracks a big effort which can span multiple issues label Mar 4, 2019
@rynowak rynowak mentioned this issue Mar 4, 2019
56 tasks
@EdCharbeneau
Copy link

EdCharbeneau commented Mar 14, 2019

I'm glad to see a milestone for this. We (Telerik) have been getting requests for this feature from customers. The description is generally "Please add HTML helper like model binding intellisense". This is definitely something developers want.

Here is one such example: Check out @robertmclaws’s Tweet: https://twitter.com/robertmclaws/status/1106267471965798411?s=09

@los93sol
Copy link

los93sol commented May 4, 2019

Yep, this is a big one. Fall thru logic seems good here. If it’s not declared on the element itself but is declared on a parent with the same condition couldn’t that type param be inferred?

@mkArtakMSFT mkArtakMSFT removed area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates labels May 9, 2019
@mkArtakMSFT mkArtakMSFT modified the milestones: 3.0.0-preview7, 3.1.0 May 28, 2019
@Liander
Copy link

Liander commented Jul 5, 2019

Regarding type inference into child contents: An observation is that when you have a context parameter assigned to an attribute you will get type inference. In other words, you would also get type inference if the context is passed to the inference method in cases when it is not used also. Then there is the problem that you don't always have a context parameter and the problem knowing which components you want to use inference on, but it indicates that there should be a construct one can use for the inference.

I did an experiment where I divided the CreateGrid inference-method into OpenGrid, AddContent and Close, where the open-grid does the inference from the (non-content) attributes and returns a TypeInference<T> singleton, which is handed over to methods building contents just for inference.

      protected void BuildRenderTree(RenderTreeBuilder builder)
      {
         builder.OpenElement(10, "div");
         TypeInference
            .OpenGrid_0(builder, 12, 13, "Data", data)
            .AddContentAttribute(builder, 14, "Columns", (typeInference_0) => (builder2) =>
               {
                  TypeInference
                     .OpenColumn_1(builder2, 16, typeInference_0, 18, "ValueSelector", person => person.Name)
                     .AddContentFunction(builder2, 19, "CellContent", (typeMap) => typeMap.T2Arg, (typeInference_1) => (value) => (builder3) =>
                       {
                          builder3.OpenElement(20, "div");
                          builder3.AddContent(21, value);  // value is here <string>
                          builder3.CloseElement();
                       })
                     .CloseComponent(builder2);
                  TypeInference
                     .OpenColumn_2(builder2, 22, typeInference_0, 23, "ValueSelector", person => person.Age)
                     .AddContentFunction(builder2, 24, "CellContent", (typeMap) => typeMap.T2Arg, (typeInference_2) => (value) => (builder3) =>
                     {
                        builder3.OpenElement(25, "div");
                        builder3.AddContent(26, value);  // value is here <int>
                        builder3.CloseElement();
                     })
                     .CloseComponent(builder2);
               })
            .CloseComponent(builder);
         builder.AddMarkupContent(27, "\r\n");
         builder.CloseElement();
      }
internal static class TypeInference
   {
      public static TypeInference<TItem> OpenGrid_0<TItem>(RenderTreeBuilder builder, int seq, 
         int __seq0, string __name0, IReadOnlyList<TItem> __arg0)
      {
         builder.OpenComponent<Grid<TItem>>(seq);
         builder.AddAttribute(__seq0, __name0, __arg0);
         return TypeInference<TItem>.Instance;
      }
      public static TypeInference<TContext, TValue> OpenColumn_1<TContext, TValue>(RenderTreeBuilder builder, int seq, TypeInference<TContext> typeInference, 
         int __seq0, string __name0, Func<TContext, TValue> __arg0)
      {
         builder.OpenComponent<Column<TContext, TValue>>(seq);
         builder.AddAttribute(__seq0, __name0, __arg0);
         return TypeInference<TContext, TValue>.Instance;
      }

The helper classes of TypeInference<…> are kept out for brevity. As one can see from the above code the inference parameters are available in sub-nodes so there is a possibility to define rules for follow-throw of defining types, however one must consider possibilities of mappings to different names.

An alternative which I think is both clearer and a great feature is to also introduce the ability to constrain contents and only accept direct child-nodes of a specific contract type instead, like having Parameter(ContentType="IColumn<TItem>"). Matching is then by type instead of name.

Hopefully this can be of some sort of inspiration.

@ghost
Copy link

ghost commented Jul 23, 2020

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@ghost
Copy link

ghost commented Oct 9, 2020

Thanks for contacting us.
We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@SteveSandersonMS
Copy link
Member

Clearing the assignment just because it was put there nearly a year ago, and there's no reason to assume who's going to be doing this in the current sprint. If Javier wants to that's totally fine, just don't want to assume that.

@SteveSandersonMS
Copy link
Member

This issue is Needs: Design. I'm writing up a design in a separate issue #29349, so closing this one in favour of that one.

@SteveSandersonMS SteveSandersonMS removed this from the 6.0-preview1 milestone Jan 15, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Feb 14, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affected-few This issue impacts only small number of customers area-blazor Includes: Blazor, Razor Components component ecosystem Indicates an issue which also has impact on 3rd party component ecosystem Components Big Rock This issue tracks a big effort which can span multiple issues enhancement This issue represents an ask for new feature or an enhancement to an existing one Needs: Design This issue requires design work before implementating. severity-blocking This label is used by an internal tool
Projects
None yet
Development

No branches or pull requests