handlebars - is it possible to access parent context in a partial?

JavascriptTemplateshandlebars.js

Javascript Problem Overview


I've got a handlebar template that loads a partial for a sub-element.

I would need to access a variable from the parent context in the calling template, from within the partial. .. doesn't seem to resolve to anything inside the partial.

Simplified code goes like this:

the template

	{{#each items}}	
		{{> item-template}}
	{{/each}}

the partial

	value is {{value}}

(obviously the real code is more complicated but it's the same principle, within the partial .. appears to be undefined.)


To show it's undefined, I've used a very simple helper whatis like this:

Handlebars.registerHelper('whatis', function(param) {
	console.log(param);
});

and updated the above code to this:

updated template

	{{#each items}}	
		{{whatis ..}}  <-- Console shows the correct parent context
		{{> item-template}}
	{{/each}}

updated partial

	{{whatis ..}}  <-- Console shows "undefined"
	value is {{value}}

Is there a way to go around that issue? Am I missing something?

EDIT: There's an open issue relating to this question on handlebars' github project

Javascript Solutions


Solution 1 - Javascript

Just in case anyone stumbles across this question. This functionality exists now in Handlebars.

Do this:

{{#each items}} 
    {{! Will pass the current item in items to your partial }}
    {{> item-template this}} 
{{/each}}

Solution 2 - Javascript

Working fiddle (inspired by handlebars pull request #385 by AndrewHenderson) http://jsfiddle.net/QV9em/4/

Handlebars.registerHelper('include', function(options) {
    var context = {},
        mergeContext = function(obj) {
            for(var k in obj)context[k]=obj[k];
        };
    mergeContext(this);
    mergeContext(options.hash);
    return options.fn(context);
});

Here's how you'd setup the parent template:

{{#each items}} 
    {{#include parent=..}}
        {{> item-template}}
    {{/include}}
{{/each}}

And the partial:

value is {{parent}}

Solution 3 - Javascript

As of 2.0.0 partials now supports passing in values.

{{#each items}}
    {{> item-template some_parent_var=../some_parent_var}}
{{/each}}

Took me awhile to find this, hope it's useful for someone else too!

Solution 4 - Javascript

The easiest way to pass the parent context to the partial is to do the loop inside the partial. This way the parent context is passed by default and when you do the loop inside the partial the {{../variable}} convention can access the parent context.

example fiddle here.

The Data

{
  color: "#000"
  items: [
    { title: "title one" },
    { title: "title two" },
  ]
}

The Template

<div class="mainTemplate">
  Parent Color: {{color}}
  {{> partial}}
</div>

The Partial

<div>
  {{#each items}}
    <div style="color:{{../color}}">
      {{title}}
    </div>
  {{/each}}
</div>

Solution 5 - Javascript

You can use some of the proposed solutions on the comments from the link to github:

https://github.com/wycats/handlebars.js/issues/182#issuecomment-4206666
https://github.com/wycats/handlebars.js/issues/182#issuecomment-4445747

They create helpers to pass the info to the partial.

Solution 6 - Javascript

I created an each Helper function that includes the parent key/values within the subcontext under the key parentContext.

http://jsfiddle.net/AndrewHenderson/kQZpu/1/

Note: Underscore is a dependency.

Handlebars.registerHelper('eachIncludeParent', function ( context, options ) {
var fn = options.fn,
    inverse = options.inverse,
    ret = "",
    _context = [];
    $.each(context, function (index, object) {
        var _object = $.extend({}, object);
        _context.push(_object);
    });
if ( _context && _context.length > 0 ) {
    for ( var i = 0, j = _context.length; i < j; i++ ) {
        _context[i]["parentContext"] = options.hash.parent;
        ret = ret + fn(_context[i]);
    }
} else {
    ret = inverse(this);
}
return ret;

});

To be used as follows:

{{#eachIncludeParent context parent=this}}
    {{> yourPartial}}
{{/eachIncludeParent}}

Access parent context values in your partial using {{parentContext.value}}

Solution 7 - Javascript

I needed dynamic form attributes for something like this...

    {{#each model.questions}}
      <h3>{{text}}</h3>

          {{#each answers}}
                {{formbuilder ../type id ../id text}}
            {{/each}}

    {{/each}}

and a helper like so...

    Handlebars.registerHelper('formbuilder', function(type, id, qnum, text, options)
    {
        var q_type = options.contexts[0][type],
            a_id = options.contexts[1].id,
            q_number = options.contexts[0][qnum],
            a_text = options.contexts[1].text;
    

            return new Handlebars.SafeString(
                    '<input type=' + q_type + ' id=' + a_id + ' name=' + q_number + '>' + a_text + '</input><br/>'
            );
    });

Which produces...

<input type="checkbox" id="1" name="surveyQ0">First question</input>

My model is a big blob of arrays and objects mixed together. What's noteworthy is that using '../' like so '../type', passes in the parent model as the context, and without it, such as with 'id', it passes in the current model as the context.

Solution 8 - Javascript

To get specifically the parent of the partial (where you may be several partials deep) then follow the other answers like SeanWM.

If you know that the parent is the main template then you can use @root which resolves to the top-most context no matter how deep you are.

e.g. {{@root.rootObject.rootProperty}}

It is a pity that ../../.. does not go up past a partial.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBenView Question on Stackoverflow
Solution 1 - JavascriptJames AndresView Answer on Stackoverflow
Solution 2 - Javascriptpward123View Answer on Stackoverflow
Solution 3 - JavascriptSeanWMView Answer on Stackoverflow
Solution 4 - JavascriptStefanHaydenView Answer on Stackoverflow
Solution 5 - JavascriptRicardo SouzaView Answer on Stackoverflow
Solution 6 - JavascriptAndrewHendersonView Answer on Stackoverflow
Solution 7 - JavascriptnullstephView Answer on Stackoverflow
Solution 8 - JavascriptEthermanView Answer on Stackoverflow