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 skips iteration on undefined values #1093

Closed
florianpilz opened this issue Sep 8, 2015 · 7 comments
Closed

#each skips iteration on undefined values #1093

florianpilz opened this issue Sep 8, 2015 · 7 comments

Comments

@florianpilz
Copy link

If I have an template like this:

{{#each data}}
<span class="{{@key}}">{{this}}</span>
{{/each}}

Handlebars will render nothing when data is a dict entry with empty value, i.e. if I render above template with

template({data: {
    'first': null,
    'second': 'bar',
}});

Only second will be rendered, but first will be ignored.

I have made a JSFiddle to demonstrate the behaviour:

I have tested the behaviour with 4.0.0 and it is skipped there as well, so it's a problem introduced in 4.0.0.

Is this the intended behaviour now? It is not stated in the documentation and I can't see a good match in the release notes. It breaks our application, since we expect to have 7 <td> columns rendered by Handlebars, but 2 are missing due to null values.

@kpdecker
Copy link
Collaborator

kpdecker commented Sep 9, 2015

This was changed due to #1065 where helpers fail when executing against a null context for non-strict mode. I would suggest using '' rather than null as this will render safely for all contexts. Baring that we might be able to implement a flag to allow for this unsafe iteration but I'm not sure on what sort of ETA that might have.

@Marsup
Copy link

Marsup commented Sep 13, 2015

Same problem with undefined values on lout for me where I try to iterate over objects.
I'm not sure I see why it's related to sparse arrays, can't we make a difference between objects and arrays ?

@kpdecker
Copy link
Collaborator

@Marsup the root problem is that helpers were being called like helper.call(undefined) and under non-strict mode this would execute against the global object leading to surprises. I'm now starting to think that it's better to:

  1. Execute for all defined keys (sparse arrays will skip elements)
  2. Fail over context execution to an empty object if not defined. i.e. something like helper.call(context || {})

It's not ideal but seems to provide the best middle ground for handling undefined in non-strict mode.

@Marsup
Copy link

Marsup commented Sep 21, 2015

You should probably explicitly check for null and undefined, other falsy values should work.

@kpdecker
Copy link
Collaborator

Good call, took that into account.

@kpdecker kpdecker changed the title #each skips entry of dict with empty value since 4.0.0 #each skips iteration on undefined values Sep 24, 2015
@kpdecker
Copy link
Collaborator

Released in 4.0.3

@florianpilz
Copy link
Author

Thanks, works like a charm!

nknapp added a commit that referenced this issue Mar 9, 2017
Fixes #1319

Original behaviour:
- When a block-helper was called on a null-context, an empty object was used
  as context instead. (#1093)
- The runtime verifies that whether the current context equals the
  last context and adds the current context to the stack, if it is not.
  This is done, so that inside a block-helper, the ".." path can be used
  to go back to the parent element.
- If the helper is called on a "null" element, the context was added, even
  though it shouldn't be, because the "null != {}"

Fix:
- The commit replaces "null" by the identifiable "container.nullContext"
  instead of "{}". "nullContext" is a sealed empty object.
- An additional check in the runtime verifies that the context is
  only added to the stack, if it is not the nullContext.
nknapp added a commit that referenced this issue Mar 9, 2017
Fixes #1319

Original behaviour:
- When a block-helper was called on a null-context, an empty object was used
  as context instead. (#1093)
- The runtime verifies that whether the current context equals the
  last context and adds the current context to the stack, if it is not.
  This is done, so that inside a block-helper, the ".." path can be used
  to go back to the parent element.
- If the helper is called on a "null" element, the context was added, even
  though it shouldn't be, because the "null != {}"

Fix:
- The commit replaces "null" by the identifiable "container.nullContext"
  instead of "{}". "nullContext" is a sealed empty object.
- An additional check in the runtime verifies that the context is
  only added to the stack, if it is not the nullContext.
nknapp added a commit that referenced this issue Mar 9, 2017
Fixes #1319

Original behaviour:
- When a block-helper was called on a null-context, an empty object was used
  as context instead. (#1093)
- The runtime verifies that whether the current context equals the
  last context and adds the current context to the stack, if it is not.
  This is done, so that inside a block-helper, the ".." path can be used
  to go back to the parent element.
- If the helper is called on a "null" element, the context was added, even
  though it shouldn't be, because the "null != {}"

Fix:
- The commit replaces "null" by the identifiable "container.nullContext"
  instead of "{}". "nullContext" is a sealed empty object.
- An additional check in the runtime verifies that the context is
  only added to the stack, if it is not the nullContext.
nknapp added a commit that referenced this issue Mar 25, 2017
Fixes #1319

Original behaviour:
- When a block-helper was called on a null-context, an empty object was used
  as context instead. (#1093)
- The runtime verifies that whether the current context equals the
  last context and adds the current context to the stack, if it is not.
  This is done, so that inside a block-helper, the ".." path can be used
  to go back to the parent element.
- If the helper is called on a "null" element, the context was added, even
  though it shouldn't be, because the "null != {}"

Fix:
- The commit replaces "null" by the identifiable "container.nullContext"
  instead of "{}". "nullContext" is a sealed empty object.
- An additional check in the runtime verifies that the context is
  only added to the stack, if it is not the nullContext.

Backwards compatibility within 4.0.x-versions:
- This commit changes the compiler and compiled templates would not work
  with runtime-versions 4.0.0 - 4.0.6, because of the "nullContext"
  property. That's way, the compiled code reads
  "(container.nullContext || {})" so that the behavior will degrade
  gracefully with older runtime versions: Everything else will work
  fine, but GH-1319 will still be broken, if you use a newer compiler
  with a pre 4.0.7 runtime.
nknapp added a commit that referenced this issue Mar 25, 2017
Fixes #1319

Original behaviour:
- When a block-helper was called on a null-context, an empty object was used
  as context instead. (#1093)
- The runtime verifies that whether the current context equals the
  last context and adds the current context to the stack, if it is not.
  This is done, so that inside a block-helper, the ".." path can be used
  to go back to the parent element.
- If the helper is called on a "null" element, the context was added, even
  though it shouldn't be, because the "null != {}"

Fix:
- The commit replaces "null" by the identifiable "container.nullContext"
  instead of "{}". "nullContext" is a sealed empty object.
- An additional check in the runtime verifies that the context is
  only added to the stack, if it is not the nullContext.

Backwards compatibility within 4.0.x-versions:
- This commit changes the compiler and compiled templates would not work
  with runtime-versions 4.0.0 - 4.0.6, because of the "nullContext"
  property. That's way, the compiled code reads
  "(container.nullContext || {})" so that the behavior will degrade
  gracefully with older runtime versions: Everything else will work
  fine, but GH-1319 will still be broken, if you use a newer compiler
  with a pre 4.0.7 runtime.
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