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

compile string to template without registering #597

Open
dexterdy opened this issue Aug 19, 2023 · 5 comments
Open

compile string to template without registering #597

dexterdy opened this issue Aug 19, 2023 · 5 comments

Comments

@dexterdy
Copy link

dexterdy commented Aug 19, 2023

Currently when I have a string in my helper that I want to transform into a template to render, I have to create a new instance of Handebars, register a template and then get the Template. I can't use the existing instance, because I don't have mutable access to it. This is a little verbose and seems unnecessary. It would be really nice if I could just use the existing instance and compile my string into a Template without registering it at all.

@dexterdy
Copy link
Author

dexterdy commented Aug 19, 2023

I have seen a previous issue with a similar question, so let me lay out my use case:

Some parts of my handlebars file has to be rendered on the client. It's rather simple to put a raw helper and a <template> tag around those parts, so that is what I did. However some parts have to be renderable on both the client and the server. The simple approach is to include a copy inside of a raw helper and a <template tag>, but I don't like that approach, because I don't like copies. Instead, I want to make a helper that does that for me. In this helper, I need access to the raw string representation of that piece of the handlebars template and simply write that back out inside a <template> tag (simple enough), but I also need to actually render the same piece of the template as well. My current solution is to register that string template inside of a new, dummy instance of handlebars and then get that template out again to call the render function on it.

That it why this functionality would be nice to have, at least in the helper functions.

@sunng87
Copy link
Owner

sunng87 commented Aug 19, 2023

@dexterdy it is possible to create a global registry and use render_template to render template string without registering.

@dexterdy
Copy link
Author

Yes, I knew about this, however this requires me to select give it the right context. It's simple when it is the top level context, because I have simple access to that in the helper function, however when the context is supposed to be a block context (like in an each block), this is a little more complicated. Can I get access to the block context for rendering with render_template?

@sunng87
Copy link
Owner

sunng87 commented Aug 20, 2023

Can you give me an example of your template and data you want to render?

It sounds like you may be able do it with a custom helper

@dexterdy
Copy link
Author

the template:

{{#each categories}}
  <div>
    {{{{bothSides "portfolio-articles-template-{{@index}}"}}}}
      {{#each articles}}
        <div class="portfolio-article">
          <span> {{title}} </span>
        </div>
      {{/each}}
    {{{{/bothSides}}}}
  </div>
{{/each}}

the result I want:

<div>
  <template id="portfolio-articles-template-0">
     {{#each articles}}
       <div class="portfolio-article">
         <span> {{title}} </span>
       </div>
     {{/each}}
  </template>
  <div class="portfolio-article">
    <span>title</span>
  </div>
</div>

the helper I wrote:

fn both_sides<'reg, 'rc>(
    h: &Helper<'reg, 'rc>,
    r: &'reg Handlebars<'reg>,
    ctx: &'rc Context,
    rc: &mut RenderContext<'reg, 'rc>,
    out: &mut dyn Output,
) -> HelperResult {
    let id = match h.param(0) {
        Some(json) => Some(
            json.value()
                .as_str()
                .ok_or(RenderError::new("id must be a string"))?,
        ),
        None => None,
    };
    let template = h.template();

    match template {
        Some(template) => {
            if template.elements.len() > 1 {
                return Err(RenderError::new("Can only be used as raw block: {{{{}}}}"));
            }

            let client_template = encase_with_template_tag(template.clone(), id);
            client_template.render(&r.clone(), ctx, &mut rc.clone(), out)?;

            let inner_string = match &template.elements[0] {
                TemplateElement::RawString(string) => string,
                _ => {
                    return Err(RenderError::new("Can only be used as raw block: {{{{}}}}"));
                }
            };
            let mut empy_handlebars = Handlebars::new();
            empy_handlebars.register_template_string("currentBothSides", inner_string)?;
            let server_template = empy_handlebars.get_template("currentBothSides").unwrap();
            server_template.render(&r.clone(), ctx, &mut rc.clone(), out)?;

            Ok(())
        }
        None => Ok(()),
    }
}

the data:

{
    "categories": [
        {
            "articles": [
                {
                    "body": "bunch of test words",
                    "subtitle": "test",
                    "title": "test",
                },
            ],
            "name": "other works",
        },
    ],
}

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

2 participants