Polymer: Computed binding not executed if argument is undefined

Created on 27 Jul 2015  Â·  9Comments  Â·  Source: Polymer/polymer

I've noticed two scenarios in which computed bindings where not executed.

  1. Binding to an undefined property:

html <span>{{ _computedBinding(blah) }}</span>

For this is does not matter if blah is a declared property or not.

  1. Binding to an undefined subproperty if the compute function has more than one argument:

html <span>{{ _computedBinding(myString, myObj.blah) }}</span>

Strangely enough, binding to an undefined property works if it is the only argument:

html <span>{{ _computedBinding(myObj.blah) }}</span>

1.x p2

Most helpful comment

As a result of this you cannot have a simple computed OR(a, b), which every user would exptect to simply work. Using a wildcard binding is not as declarative, and it actually fires too often. That's a bug introduced by design and I hope for a fix rather sooner than later.

All 9 comments

Hi, @MaKleSoft --

I noticed this previously, as well. As it turns out, what you're seeing is by design. See kevin's helpful response here:

https://github.com/Polymer/polymer/issues/1874#issuecomment-112260054

Thanks, @robrez, that clears things up somewhat. Doesn't explain the inconsistent behavior though.

These behaviors are by design.

I grant that when compared side-by-side it may be counter-intuitive, but there are actually just two rules that govern the current behavior:

  • Effects "go" when dependencies are _pushed_

    • _Rationale: we do not "pull" dependencies; rather effects go when dependencies are set_

  • Effects with multiple dependencies "go" when all values are defined

    • _Rationale: we do this to provide an ergonomic benefit to avoid needing undefined checks (since effects would run for each value being set in sequence), and as a performance benefit for the initial use (so the effect is only run once, e.g. at startup or when initially setting all values)

Thus from your examples above:


    1. The computing function runs only once blah has been set (to any value, including undefined)

  • 2a. The computing function runs once myString and myObj.blah are set (but only to non-undefined values, per the second rule)
  • 2b. Same as 1, the computing function runs once myObj.blah is set; note that setting myObj to any value will result in myObj.blah being pushed to the computing function (which may be undefined in the case of myObj = {})

That said, we have been exploring refinements to these rules based on feedback.

Possibilites include:

  • Don't run single-property observers when undefined is pushed (would make it a single rule: "Effects go once all dependencies are defined")

    • This is practically be fine as long as users don't ever manually set undefined, which we highly discourage and treat as an anti-pattern anyway

  • Currently, the binding system "sets" undefined when a path evaluates to undefined (e.g. {{myObj.noPropHere}}); since this would violate the "don't set undefined rule", we are considering having the binding system use the default value of a target property in place of undefined

As a result of this you cannot have a simple computed OR(a, b), which every user would exptect to simply work. Using a wildcard binding is not as declarative, and it actually fires too often. That's a bug introduced by design and I hope for a fix rather sooner than later.

@kaste or @kevinpschaaf, what's a workaround for OR(a, b) when properties might be undefined?

Almost an year and a half since this issue was posted and this still hasn't been solved?

I found myself in a position where I need a very simple OR(a, b) computation, just like @kaste commented, but that doesn't work as expected.

As @kevinpschaaf explained:

Effects "go" when dependencies are pushed

What if both dependent properties have declared values to be used as default value? Why do they still need to be "set" to be considered resolved?

I'm pretty sure it can all go down to a simple check.

Does the property have declared value?

(yes) ==> Push effects once at the beginning.
(no) ==> Wait for it to be set (current behavior).

This way you even won't have to break your "don't set undefined rule". If it's undefined and no value has been declared simply don't do anything – responsibility goes to the coder to choose a default "not yet set" value and handle it.

As an example for my case in particular, I need to display a bar holding a (String) heading and a subHeading. The bar should be displayed when either of the properties are defined. However, for the cases where only heading or only subHeading is set, the bar is not displayed :(

I've declared both properties to a false as default value, which even differs from an empty string, so I always know when either has been set, even if it's empty. null is also an option, again – coder's responsibility.

+1

+1

Observers run with undefined in Polymer 2 as described in the upgrade guide, therefore I am closing this issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

paranoid-android picture paranoid-android  Â·  3Comments

masaoliou picture masaoliou  Â·  3Comments

abdonrd picture abdonrd  Â·  4Comments

ghost picture ghost  Â·  4Comments

bmodeprogrammer picture bmodeprogrammer  Â·  3Comments