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

each overwrites data in the "data" property. #1327

Closed
janthonyeconomist opened this issue Mar 15, 2017 · 14 comments · Fixed by renovatebot/renovate#216
Closed

each overwrites data in the "data" property. #1327

janthonyeconomist opened this issue Mar 15, 2017 · 14 comments · Fixed by renovatebot/renovate#216

Comments

@janthonyeconomist
Copy link

I am using handlebars as the templating engine of a gulp-metalsmith build system. I am using the metalsmith-data-loader to load a JSON file into the a data property; however, when I go to access that property in then handlebars template it is not the value of true. It seems to be linked to the access of the @index in an each block helper.

I presume the problem is in: handlebars.js/lib/handlebars/helpers/each.js however, I don't know enough about the expected params to really grok the problem.

@nknapp
Copy link
Collaborator

nknapp commented May 13, 2017

I would be helpful if you could separated this problem from gulp-metalsmith can you reproduce the behaviour with the jsfiddle linked in CONTRIBUTING.md.

The would be helpful for examining the problem.

@janthonyeconomist
Copy link
Author

I think this problem is because how consolidate implements handlebars. If you look at node_modules/consolidate/lib/consolidate.js there is a function:

exports.handlebars.render = function(str, options, fn) {
  return promisify(fn, function(fn) {
    var engine = requires.handlebars || (requires.handlebars = require('handlebars'));
    try {
      for (var partial in options.partials) {
        engine.registerPartial(partial, options.partials[partial]);
      }
      for (var helper in options.helpers) {
        engine.registerHelper(helper, options.helpers[helper]);
      }
      var tmpl = cache(options) || cache(options, engine.compile(str, options));
      fn(null, tmpl(options));
    } catch (err) {
      fn(err);
    }
  });
};

It is passing the data object into the compile method.

You can see it reproduced here: https://jsfiddle.net/9D88g/105/
And it works without the @Index here: https://jsfiddle.net/9D88g/106/

@janthonyeconomist
Copy link
Author

Should I move this ticket over to the "consolidate" people?

@nknapp
Copy link
Collaborator

nknapp commented May 17, 2017

I'll have a look. Let me see if I understand what your problem ist.

@nknapp
Copy link
Collaborator

nknapp commented May 17, 2017

No, keep it here. I think you did a pretty good job extracting the problem and it definitely looks wrong to me.
You are expecting the output

0: foo
1: bar

correct?

@janthonyeconomist
Copy link
Author

yeah. (with the obvious exception of the line break)

@nknapp
Copy link
Collaborator

nknapp commented May 17, 2017

It works, if you change "data" to "datax" (https://jsfiddle.net/9D88g/111/)
Just in case this helps, but I'm still investigating

@janthonyeconomist
Copy link
Author

Thanks.

Luckily I discovered this before I even created the ticket. The problem seems to be the very specific property data. That is why I assumed the problem was in handlebars.js/lib/handlebars/helpers/each.js, as it uses that property name when setting up the context of a loop. This might also explain why the problem only occurs when you use the @index variable in a loop.

@nknapp
Copy link
Collaborator

nknapp commented May 17, 2017

Well, may be it is something for the consolidate people, maybe not. There room to argue...
In fact, I have just understood what you said in your comment

It is passing the data object into the compile method.

Yes, that is problematic because of this piece of code. Now, I don't fully understand why consolidate is passing the data-object to the compile-method and I would say you shouldn't do that.

On the other hand, it can be argued that Handlebars.compile should not alter the options object. I'm not sure if that's documented somewhere...

Could you open an issue at consolidate? I'd like to hear (read) their point of view before changing anything at Handlebars.

@nknapp
Copy link
Collaborator

nknapp commented May 17, 2017

Oh, I didn't see your last post... I think I will have a look what could be done for not altering the options during compilation. I don't know the code well enough yet to see if it has any impact on the interface.

But this might take a while and I can't continue right now.

@janthonyeconomist
Copy link
Author

I'll raise the issue to the consolidate people as well and link to this issue.

@janthonyeconomist
Copy link
Author

Perhaps the best thing is to clone the options went they are passed in, so that they can be immutable. Not ideal, but might be enough.

I have opened a ticket with consolidate: tj/consolidate.js#280

nknapp added a commit to nknapp/handlebars.js that referenced this issue May 18, 2017
Fixes handlebars-lang#1327

- This commit creates a shallow copy of the "options" passed to
  Handlebars.compile() in order to prevent modifications
- Note that "new Handlebars.Compiler().compile(..., options)" still
  modify the options object. This might change in the future, if
  anybody needs a fix for that.
@nknapp
Copy link
Collaborator

nknapp commented May 18, 2017

I have opened a PR, if anyone would like to comment, please do it there.
I'll leave it open for a day or two and merge it then.

@nknapp nknapp closed this as completed in 8a836e2 May 21, 2017
@nknapp
Copy link
Collaborator

nknapp commented May 21, 2017

After a broken 4.0.9-release (because Object.assign is not supported by IE), this issue is now resolved in 4.0.10

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

Successfully merging a pull request may close this issue.

2 participants