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

Nodes do not appear in this.$ when they become visible after a <template if=""> condition has been met. #642

Closed
hesamrabeti opened this issue Jul 17, 2014 · 15 comments

Comments

@hesamrabeti
Copy link

Nodes do not appear in this.$ when they become visible after a <template if=""> condition has been met.

As an example, if the element below is instantiated and at some later time element.setDone() and element.printValue() are executed sequentially, the console.log() command in printValue() fails with a null pointer dereference.

<polymer-element name="x-element">
  <template>
    <template if="{{done}}">
      <paper-input id="input"></paper-input>
    </template>
  </template>

<script>
Polymer('x-element', {
  setDone: function() {
    this.done = true;
  }.

  printValue: function() {
    console.log(this.$.input.value);
  }
});
</script>
</polymer-element>
@jarrodek
Copy link

I just wanted to file this issue also.
I can confirm this behavior and as well have a problem with it.

@ebidel
Copy link
Contributor

ebidel commented Jul 18, 2014

This is a great source of frustration for many folks that I'd love to see use support it someday. this.$ holds entries only for static elements with IDs and not for elements dynamically produced by bound templates.

See Polymer/old-docs-site#460

@balupton
Copy link

I've ended up adding the following myself:

<script>
    Node.prototype.$find = function(selector){
        return jQuery(this.shadowRoot.querySelectorAll(selector))
    }
</script>

Which then allows me to do this.$find('.someClass').hide(). Perhaps others will find it useful too.

Without jQuery, you could probably do:

<script>
    Node.prototype.find = function(selector){
        return this.shadowRoot.querySelectorAll(selector)
    }
</script>

Just as a shorthand.

@sjmiles
Copy link
Contributor

sjmiles commented Aug 18, 2014

I acknowledge that this is a stumbling block for many users, unfortunately it's not so easy to fix.

  1. The existing mechanism is designed for performance: this is (partly) why the $ is a simple hash and is populated only once.
  2. Using conditional templates for dynamic display is generally a bad idea and is an underlying misconception that has bad effects on projects using Polymer (problems with $ is just is one of the symptoms, the other obvious issue is performance loss).
  3. Referencing nodes at all is also generally a bad idea. Using binding and event delegation to separate view and presenter is much preferred. We need to understand why people are wanting to use $ in dynamic scenarios.

Also note that this.shadowRoot.query* is an anti-pattern because an element method can operate inside a subclass that may have installed additional shadow-roots. Proper solutions for dynamic element finding need another piece of disambiguating information, for example, the name of a superclass, or a static element (in $) to query from. This is another reason to emphasize (3).

@hesamrabeti
Copy link
Author

An example of using $ in a conditional template is getting the value of the
text of a text box.
On Aug 18, 2014 11:29 AM, "Scott J. Miles" notifications@github.com wrote:

I acknowledge that this is a stumbling block for many users, unfortunately
it's not so easy to fix.

  1. The existing mechanism is designed for performance: this is
    (partly) why the $ is a simple hash and is populated only once.
  2. Using conditional templates for dynamic display is generally a bad
    idea
    and is an underlying misconception that has bad effects on
    projects using Polymer (problems with $ is just is one of the
    symptoms, the other major issue is performance loss).
  3. Referencing nodes at all is also generally a bad idea. Using
    binding and event delegation to separate view and presenter is much
    preferred. We need to understand why people are wanting to use $ in
    dynamic scenarios.

Also note that this.shadowRoot.query* is an anti-pattern because an
element method can operate inside a subclass that may have installed
additional shadow-roots. Proper solutions for dynamic element finding need
another piece of disambiguating information, for example, the name of a
superclass, or a static element (in $) to query from. This is another
reason to emphasize (3).


Reply to this email directly or view it on GitHub
#642 (comment).

@sjmiles
Copy link
Contributor

sjmiles commented Aug 18, 2014

<text-area> is problematic for binding, but this is highly specific and potentially solvable via Node.bind.

Also, there is the question of whether there is value in the text box being in a conditional template instead of being modulated via display style or factored into a different element.

@davenotik
Copy link

(I had the same issue: http://stackoverflow.com/questions/25651295/html-elements-wrapped-with-a-condition-are-null-in-when-my-polymer-element-calls.) So, several anti-patterns and bad ideas are mentioned here, but if not template if conditionals, are there some docs or a full fledged code sample of the proper pattern? Some best practices would go a long way.

@ebidel
Copy link
Contributor

ebidel commented Sep 3, 2014

@davenotik
Copy link

Yes, but that seems pretty hacky. Best practices are what I'm after, rather than forcefully doing it the way I want to. Do you think my answer posted on SO is a better approach? http://stackoverflow.com/questions/25651295/html-elements-wrapped-with-a-condition-are-null-in-when-my-polymer-element-calls/25653991#25653991

@ebidel
Copy link
Contributor

ebidel commented Sep 3, 2014

Why hacky? It's utilizing a built-in Polymer feature and avoids the pitfalls of using this.shadowRoot.querySelector() when the element is extending another.

@davenotik
Copy link

Sorry, I don't think I quite got it the first time. So in that example, you're surrounding the template conditional with a node that will be added to $, thereby giving a means to access the stuff inside the template conditional that wasn't there when $ was populated. I like it.

And so I fully understand, what are those pitfalls "when the element is extending another"? Thanks so much. This is great fundamental stuff. Your docs are comprehensive, but a lot of is tough to grasp for less advanced developers like myself, I think. Some kind of "you want to do this, therefore know these concepts" approach might help, where here it's like an index of concepts and I'm not sure what's relevant to my case. Thank you!

@RenaudF
Copy link

RenaudF commented Oct 24, 2014

I have a somewhat similar issue so I'm going to add to this one, feel free to open a new issue if it's not related. Here is the stackoverflow and the jsfiddle

@nomego
Copy link

nomego commented Dec 11, 2014

As described in googlearchive/TemplateBinding#205, "automatic node finding" actually works in a conditional template if the condition is true the first time the template is rendered.
This, however, makes it an even larger bug with an even greater pitfall since the behavior actually isn't consistent.

@tjsavage
Copy link
Contributor

Closing this issue due to age and the release of version 1 of Polymer - please feel free to re-open if this is incorrect.

@abhinavmca0909
Copy link

plz give me one example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

11 participants