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

Support content projection in data-sly-template #67

Open
adam-cyclones opened this issue Aug 8, 2018 · 6 comments
Open

Support content projection in data-sly-template #67

adam-cyclones opened this issue Aug 8, 2018 · 6 comments
Assignees

Comments

@adam-cyclones
Copy link

adam-cyclones commented Aug 8, 2018

In Angular and a multitude of other templating languages, it is possible to declare slots where templates can hold injected html, this is known as content projection, it is a method in which layout and content of layout are separated. This means that a template becomes extremely flexible and quick to refactor. I have found a very hacky way to do this currently (not practical in prod).

The workaround:

<sly data-sly-template.contentProjectionTest="${ @ FormInputSlot1, FormInputSlot2 }">
    <form>
        <div class='form-control-group-1'>
            ${FormInputSlot1 @context="html"}
        </div>
        <div class='form-control-group-2'>
            ${FormInputSlot2 @context="html"}    
        </div>
    </form>
</sly>

<!--/* Hacky variables for html as a string */-->
<sly data-sly-test.injectedContentToSlot="${'
    <label>creates a slot to inject content</label>
    <input type=\'text\' value=\'Hello world\'>
'}"></sly>

<sly data-sly-test.injectedContentToSlot2="${'
    <label>creates a slot to inject content</label>
    <h1>varient</h1>
'}"></sly>

<!--/* render and inject */-->
<sly data-sly-call="${contentProjectionTest @ 
    FormInputSlot1=injectedContentToSlot, 
    FormInputSlot2=injectedContentToSlot2
}"></sly>

This is less than ideal for several reasons
• Escaped quotes
• Markup as a string
• Involved setup
• No ability to have slot contents imported from files

I propose that the functionality could look like this:

<sly data-sly-template.contentProjectionTest>
    <form>
        <!--/*much more flexible template layout*/-->
        <div class='form-control-group-1'>
            <sly data-sly-slot="${contentProjectionTest @ FormInputSlot1}"/>
        </div>
        <div class='form-control-group-2'>
            <sly data-sly-slot="${contentProjectionTest @ FormInputSlot2}"/>
        </div>
    </form>
</sly>

<sly data-sly-call="${contentProjectionTest}">
    <sly data-sly-push="${contentProjectionTest @ FormInputSlot1}">
        <label>creates a slot to inject content</label>
        <input type=\'text\' value=\'Hello world\'>
    </sly>
    <sly data-sly-push"${contentProjectionTest @ FormInputSlot2}">
        <label>creates a slot to inject content</label>
        <h1>varient</h1>
    </sly>
</sly>`

I'd love to hear your thoughts.

@raducotescu
Copy link
Member

@acronamy, I have the impression that you can already achieve this, with two or more templates:

HTL script:

<template data-sly-template.inner>
    <span>This is the inner template.</span>
</template>

<template data-sly-template.outer>
    <span class="outer" data-sly-call="${inner}"></span>
</template>

<div class="wrapper" data-sly-call="${outer}"></div>

Output:

<div class="wrapper">
    <span class="outer">
        <span>This is the inner template.</span>
    </span>
</div>

Does this example fit your use-case?

@raducotescu raducotescu self-assigned this Aug 20, 2018
@adam-cyclones
Copy link
Author

adam-cyclones commented Aug 21, 2018

@raducotescu thanks for your reply, this is a better workaround than my own.

That sounds about right in the simplest use case, In the real world, I wouldn't have 2 templates in the same file as one would be /layouts/column.html and the other /content/select-list.html however so I would data-sly-use the content, so that means the inner template would have to be passed as a parameter. I use parameters in templates for attributes, text content and conditionals. I feel that this inner html insertion via params is a different idea from my current usage or params, which (is imo), not as clear using the method mentioned, a dedicated data-sly method would do more for clarity.

@jantimon
Copy link

Some years ago I had the same idea but I have never created a proposal.
Maybe the syntax could be changed but the idea of @adam-cyclones is essential for modern modularisation.

The feature is supported by all modern frontend rendering engines like react, angular or vue.

But also common rendering engines like handlebars support it

Angular:

<dashboard-tile a="10" b="5" c="15">
    Only believe in statistics you've faked yourself.
  </dashboard-tile>

React:

<DashboarTile a="10" b="5" c="15">
    Only believe in statistics you've faked yourself.
</DashboarTile>

Vue:

<dashboard-tile a="10" b="5" c="15">
    Only believe in statistics you've faked yourself.
</dashboard-tile>

Handlebars:

{{#dashboard-tile a="10" b="5" c="15"}}
    Only believe in statistics you've faked yourself.
{{/dashboard-tile}}

Why do I believe that the current htl solution proposed by @raducotescu is not enough?

Lets say you wrote an abstraction for a container, grid row, a grid column, a accordion and a typography:

<Container>
  <Row vertical-alignment="top">
     <Column size="4">
         <Typography size="xl" responsive font="light">Hello World</Typography>
      </Column>
     <Column size="8">
         <Accordion collapsed>
             <Typography size="m" responsive font="medium">Some text about world</Typography>
          </Accordion>
      </Column>
  </Row>
  <Row vertical-alignment="top">
     <Column size="8">
         <Typography size="xl" responsive font="light">Hello Mars</Typography>
      </Column>
     <Column size="4">
         <Accordion collapsed>
             <Typography size="m" responsive font="medium">Some Text about <a href="moon">moon</a></Typography>
          </Accordion>
      </Column>
  </Row>
</Container>

Maybe @raducotescu could correct me but I believe there is no good way to build reusable components similar to the example above in htl.

@raducotescu
Copy link
Member

@jantimon, you're right, HTL's templates are not as advanced. I'll take this issue to our team and we'll try to figure out how it would work.

@jantimon
Copy link

jantimon commented Jul 21, 2020

@raducotescu do you have any update for us?

I guess the most simple way would be the following:

<sly data-sly-template.headline="${ @ children }">
    <h1>${children}</h1>
</sly>

<sly data-sly-call="${headline}">
   Hello World
</sly>

It would be backwards compatible and very similar to react or handlebars

@adam-cyclones
Copy link
Author

6 months ago I raised this. It's an important feature and I hope it gets added. I no longer work on AEM for one of your bigger clients so I have no vested interest. But it's interesting to see how it would be solved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants