Skip to content

Implementation of RenderFragment<T> #15829

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

Closed
uazo opened this issue Jul 7, 2018 · 6 comments
Closed

Implementation of RenderFragment<T> #15829

uazo opened this issue Jul 7, 2018 · 6 comments
Labels
area-blazor Includes: Blazor, Razor Components

Comments

@uazo
Copy link
Contributor

uazo commented Jul 7, 2018

I would like to submit a possible implementation of RenderFragment<T> to the Blazor community. Source code is here: https://github.com/uazo/Blazor/tree/dev-experimental-templated-component.
This time before doing a pull request I ask here :)

An example is worth a thousand words:

<ComponentTemplateTest>
    <ComponentTemplateTest.Template>
        test simple template
    </ComponentTemplateTest.Template>

    <ComponentTemplateTest.TemplateWithInt WithParams="param1">
        @param1
    </ComponentTemplateTest.TemplateWithInt>

    <ComponentTemplateTest.TemplateWithObject WithParams="paramObject">
        <div>
            propint = @paramObject.PropInt
        </div>
        <div>
            PropString = @paramObject.PropString
        </div>
    </ComponentTemplateTest.TemplateWithObject>

    <div>this is childcontent (1)</div>
    <div>this is childcontent (2)</div>
</ComponentTemplateTest>

will be renderer as

builder.OpenComponent<StandaloneApp.Pages.testtemplated.ComponentTemplateTest>(3);
builder.AddAttribute(4, "ChildContent", (Microsoft.AspNetCore.Blazor.RenderFragment)((builder2) => {
    builder2.OpenElement(5, "div");
    builder2.AddContent(6, "this is childcontent (1)");
    builder2.CloseElement();
    builder2.OpenElement(7, "div");
    builder2.AddContent(8, "this is childcontent (2)");
    builder2.CloseElement();
}
));
builder.AddAttribute(9, "Template", (Microsoft.AspNetCore.Blazor.RenderFragment)((builder2) => {
    builder2.AddContent(10, "\n        test simple template\n    ");
}
));
builder.AddAttribute(11, "TemplateWithInt", (Microsoft.AspNetCore.Blazor.RenderFragment<System.Int32>)((builder2, param1) => {
    builder2.AddContent(12, "\n        ");
    builder2.AddContent(13, param1);
    builder2.AddContent(14, "\n    ");
}
));
builder.AddAttribute(15, "TemplateWithObject", (Microsoft.AspNetCore.Blazor.RenderFragment<StandaloneApp.Pages.testtemplated.ComponentTemplateTest.TestObject>)((builder2, paramObject) => {
    builder2.AddContent(16, "\n        ");
    builder2.OpenElement(17, "div");
    builder2.AddContent(18, "\n            propint = ");
    builder2.AddContent(19, paramObject.PropInt);
    builder2.AddContent(20, "\n        ");
    builder2.CloseElement();
    builder2.AddContent(21, "\n        ");
    builder2.OpenElement(22, "div");
    builder2.AddContent(23, "\n            PropString = ");
    builder2.AddContent(24, paramObject.PropString);
    builder2.AddContent(25, "\n        ");
    builder2.CloseElement();
    builder2.AddContent(26, "\n    ");
}
));
builder.CloseComponent();

and to use simple as

<div>Template with parameter (int): @TemplateWithInt?.Render(testobject.PropInt)</div>

a complete example is provided in StandaloneApp.

I'm using <ComponentTemplateTest.Template> to define the value of RenderFragment property but it isn't mandatory. We can use only <Template> but if there is a component with that name it will not work. In this way the possibility of homonyms is excluded.
The attribute WithParams is used to specify the name of the local variable, so that it is the developer who uses the component to decide the name.

The changes are all in the extension.
I have not introduced any breaking changes, so ChildContent keeps working.
The test cases are missing, but I could not find those related to ChildContent to understand how they work (never done test cases before!)

Unfortunately there are some imperfections in intellisense that I can not fix:

  1. I can not stop showing all the standard helpers tags (defined in BindTagHelperDescriptorProvider.cs) for the new template tags. I think it's a limitation of TagMatchingRule that does not allow to define tags to be excluded. If "Microsoft.VisualStudio.Web.Editors.Razor" would expose "TagHelperScriptOrStyleTagNameService" I could edit "TagHelperFactsService" and introduce new rules, but I did not understand how.

  2. When writing <ComponentTemplateTest.Template> Intellisense shows comments in the popups that I can not hide.

However it seems to work.
I would be happy to contribute to this wonderful project: if there is something to change or improve I am available for sure.

@uazo
Copy link
Contributor Author

uazo commented Jul 7, 2018

just one more thing.
The name TemplateWithInt and the tag <ComponentTemplateTest.TemplateWithInt> in only because the property is defined as

  [Parameter]
  public RenderFragment<int> TemplateWithInt { get; set; }

it can be anything, as long as the property is a RenderFragment!

@LunicLynx
Copy link
Contributor

I really like this!

Does this also work with server side?

@rynowak
Copy link
Member

rynowak commented Aug 23, 2018

Hi @uazo - I'm currently looking at implementing RenderFragment<T> and support for creating them using the existing Razor templates feature. This will look something like:

@functions {
    RenderFragment<Person> PersonTemplate = @<div>@item.Name - @item.Age</div>
}

We'll do more with this, but I'm starting here for now since this is an existing Razor feature that isn't yet supported in Blazor land. Is there any overlap of this with what you've done?

@uazo
Copy link
Contributor Author

uazo commented Aug 25, 2018

Hi @rynowak . My work allowed a way to define a RenderFragment<T> for the properties of a component, "inline with the html" to say, with still the doubt whether to use WithArgs or not (https://github.com/aspnet/Blazor/issues/404#issuecomment-403283107 https://github.com/aspnet/Blazor/issues/404#issuecomment-403295764 https://github.com/aspnet/Blazor/issues/404#issuecomment-410556289)
Adding the ability to define it via code would complete the task.

I think, however, that a syntax like this would allow the use of any variable name.

RenderFragment<Person> PersonTemplate = (item) => @<div>@item.Name - @item.Age</div>

Also, what about the sintax for the html? Like this? Is it supported?

<ComponentTemplateTest2
    RowTemplate=@<div>item.Name</div>
 ></ComponentTemplateTest2>

I have updated branch with master, so you can see only my changes

@uazo
Copy link
Contributor Author

uazo commented Aug 25, 2018

Does this also work with server side?

@LunicLynx yes, just because is a compiler time feature

@rynowak
Copy link
Member

rynowak commented Aug 25, 2018

I think, however, that a syntax like this would allow the use of any variable name.
RenderFragment PersonTemplate = (item) => @

@item.Name - @item.Age

I agree that something like that would be ideal but it would require changes to the core of Razor to work well. We'll be making changes to Razor to improve Blazor's scenarios as part of 3.0 but the time frame for making that available in editors is somewhat distant.

Also, what about the sintax for the html? Like this? Is it supported?

The PR I sent yesterday adds support for passing a template 'inline' as a component parameter. This is also something that regular Razor doesn't support (templates inside attributes) and so there is some buggy behavior around completion and colorization. For instance colorization of markup inside the attribute doesn't work.

@uazo uazo closed this as completed Sep 14, 2018
@mkArtakMSFT mkArtakMSFT transferred this issue from dotnet/blazor Oct 27, 2019
@mkArtakMSFT mkArtakMSFT added the area-blazor Includes: Blazor, Razor Components label Oct 27, 2019
@ghost ghost locked as resolved and limited conversation to collaborators Dec 3, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

No branches or pull requests

4 participants