Handlebars.js: Is it possible to render a partial without the parent scope?

Created on 27 May 2015  Â·  11Comments  Â·  Source: handlebars-lang/handlebars.js

I'm trying to treat partials as "components" that only have access to variables that were passed in as attributes — is this possible?

my-partial.hbs

<div class="my-partial">
  <!-- should only be displayed if it was passed in as an attribute -->
  {{#if name}}
    Hello, {{name}}
  {{/if}}
</div>

my-app.js

const data = { name: 'Adam' }

my-app.hbs

Hello, my name is {{name}} and is available in the template scope
{{> myPartial}}
{{> myPartial name="John"}}

Actual output

Hello, my name is Adam and is available in the template scope
<div class="my-partial>
  Hello, Adam
</div>
<div class="my-partial>
  Hello, John
</div>

Desired output

Hello, my name is Adam and is available in the template scope
<div class="my-partial"></div>
<div class="my-partial">
  Hello, John
</div>

Most helpful comment

Passing a first argument to the partial call will render in its own context, independent of the parent. I.e. {{> myPartial newContext name="foo"}}

All 11 comments

Here's my current workaround:

Handlebars.registerHelper('component', (partial, options) => {
  const template = Handlebars.compile(Handlebars.partials[partial])
  const html = template(options.hash)
  return new Handlebars.SafeString(html)
})
{{component "myPartial" name="Adam"}}

Passing a first argument to the partial call will render in its own context, independent of the parent. I.e. {{> myPartial newContext name="foo"}}

Why is that not the default behavior? That was a rude shock when I found out.

How exactly would we default to providing a context from an arbitrary variable without the author selecting that variable by name?

I'm not sure I understand. If a set of key-value pairs were provided
that would form the object used as the context. For example if I had a
partial like this:

{{> radioButton name="enabled" value="true" id="enableUser"
labelText="Enable User"}}

The object used as a context would be:
{
name: "enabled",
value: "true",
id: "enableUser"
labelText: "Enable User"
}

I don't know how it works now internally (I'm just a user).

On 8/7/15, Kevin Decker [email protected] wrote:

How exactly would we default to providing a context from an arbitrary
variable?


Reply to this email directly or view it on GitHub:
https://github.com/wycats/handlebars.js/issues/1032#issuecomment-128866509

@rayHInstart Those keys are added to the existing context to form a new context that has both sets of data, with the explicitly passed hash parameters given priority. This has a performance impact vs. some of the alternatives, but outside of that I'm not sure what was quite so rude or shocking. Glad to discuss any changed to behavior you'd like to see but please outline it fully as well as outline the issues that you've seen from the existing behavior.

In my use case, I had a partial which used a common variable name,
something like

{{#if disabled}}Hi, I'm disabled{{/if}} {{#unless disabled}}I'm super active!{{/unless}}

And I used it like this:
{{> superPartial }}

, expecting that since I did not explicitly pass a disabled into the
context, it would assume that disabled wasn't present. Unfortunately,
I had a completely unrelated variable named "disabled" in the template
object, so the partial kept rendering as if disabled were true, even
though I hadn't passed it in to the partial. I didn't expect this
behavior at all, and it took me quite a while to figure out what was
going on (couldn't easily find in the documentation a description of
this behavior). The partial is in a separate file, and I'm passing in
variables to the partial, so I assumed that the partial would always
have a completely different context than the parent. Since partials
are intended to be reused as parts of different templates, I would
think that their context would be compartmentalized away from the
parent context -- the partial shouldn't rely on the parent template
since that breaks encapsulation. I imagined the partial to be a
function which I was passing arguments to. I'm very glad that
Handlebars allows this capability if I tell it explicitly that I want
a new context for the partial, but to me it's counterintuitive that I
would have to tell it to do that. I think the expected behavior should
be that a partial always has its own context; if a user wants to
override and inherit from the parent context, there can be a flag to
do that, but it should be explicit.

On 8/12/15, Kevin Decker [email protected] wrote:

@rayHInstart Those keys are added to the existing context to form a new
context that has both sets of data, with the explicitly passed hash
parameters given priority. This has a performance impact vs. some of the
alternatives, but outside of that I'm not sure what was quite so rude or
shocking. Glad to discuss any changed to behavior you'd like to see but
please outline it fully as well as outline the issues that you've seen from
the existing behavior.


Reply to this email directly or view it on GitHub:
https://github.com/wycats/handlebars.js/issues/1032#issuecomment-130551984

Regarding documentation, the behavior is covered here but as with all documentation, what makes sense to someone who already knows the code is not always the same for others.

Will render the partial named myPartial. When the partial executes, it will be run under the current execution context.

I did not write the original implementation of this so I can't really comment on why the decisions were made as they were, but I can say that changing this is difficult. Many of these arguments are completely valid but like most issues filed with Handlebars of late, counter arguments can be made to equal degree, and for those cases "don't break existing code" generally wins.

I don't think it will be much overhead to add a flag that requires explicit contexts to be passed for partials which I can look at for this release, but we aren't going to be able to change the existing behavior. This does little to account for confusion of users just starting with the language, but would allow for your use case with out nasty temporary objects or similar hacks.

Thanks Kevin. "Don't break existing code" is indeed a winning
argument. That is a flag I would definitely use :).

On 8/14/15, Kevin Decker [email protected] wrote:

Regarding documentation, the behavior is covered
here but as with all documentation,
what makes sense to someone who already knows the code is not always the
same for others.

Will render the partial named myPartial. When the partial executes, it
will be run under the current execution context.

I did not write the original implementation of this so I can't really
comment on why the decisions were made as they were, but I can say that
changing this is difficult. Many of these arguments are completely valid but
like most issues filed with Handlebars of late, counter arguments can be
made to equal degree, and for those cases "don't break existing code"
generally wins.

I don't think it will be much overhead to add a flag that requires explicit
contexts to be passed for partials which I can look at for this release, but
we aren't going to be able to change the existing behavior. This does little
to account for confusion of users just starting with the language, but would
allow for your use case with out nasty temporary objects or similar hacks.


Reply to this email directly or view it on GitHub:
https://github.com/wycats/handlebars.js/issues/1032#issuecomment-131228073

Released in 4.0.0

To reference local variable specifically inside partial and not allow to "leak" from the outer context use:

@this.myVariable
Was this page helpful?
0 / 5 - 0 ratings