How to access content of dom-if inside a custom el

2019-02-24 06:38发布

In a custom element I want to access a span and append a child to it but all usual accessors give undefined:

<template>
    <template is="dom-if" if="[[condition]]" restamp>
        <span id="myspan"></span>
    </template>
</template>

 ready() {
   var a = this.$.myspan;                     //<------- is undefined
   var b = this.$$.myspan;                    //<------- is undefined
   var c = document.getElementById("myspan"); //<------- is undefined
   var d = this.$$("#myspan");                //<------- is undefined
}

How to access a span in this case?

UPDATE: here is plunk

4条回答
混吃等死
2楼-- · 2019-02-24 07:13

Try to do it asynchronously in the attached method as follows, this method works:

attached: function(){
   this.async(function(){
     var d = this.$$("#myspan"); 
     console.log(d); 
   },someTimeIfThereAreManyItemsToLoad);
}
查看更多
狗以群分
3楼-- · 2019-02-24 07:19

The reason this didn't work inside the lifecycle callback without setTimeout or this.async is that right after attaching your element the dom-if template has not yet rendered. Upon attaching your element, Polymer calls the attached callback. However, when the value gets set on the the dom-if, an observer runs and debounces its own _render function. The debounce waits an amount of time to catch any other calls to it, and then it executes the ._render function and attaches the element to the DOM. In other words, when the attached callback runs, normally the dom-if template hasn't rendered yet.

The reason for this debounce is performance. If several changes were made within a very short span of time, this debounce prevents the template from rendering several times when the result we would care about is the end result.

Fortunately, dom-if provides a .render() method which allows you to make it render synchronously. All you need to do is add an id to your dom-if, switch to an attached callback and call like this:

<template>
    <template id="someDomIf" is="dom-if" if="[[condition]]" restamp>
        <span id="myspan"></span>
    </template>
</template>

 attached() {
   this.$.someDomIf.render();
   var c = document.getElementById("myspan"); //<------- should be defined
   var d = this.$$("#myspan");                //<------- should be defined
}

Triggering a synchronous render on the dom-if shouldn't be a huge performance problem, since luckily your element should only be getting attached once. Edit: As it turns it, this even works in a ready callback:

<template>
    <template id="someDomIf" is="dom-if" if="[[condition]]" restamp>
        <span id="myspan"></span>
    </template>
</template>

 ready() {
   this.$.someDomIf.render();
   var c = document.getElementById("myspan"); //<------- should be defined
   var d = this.$$("#myspan");                //<------- should be defined
}

See this fork of your plunker: http://plnkr.co/edit/u3richtnt4COpEfx1CSN?p=preview

查看更多
我命由我不由天
4楼-- · 2019-02-24 07:23

As in Polymer documentation:

Note: Nodes created dynamically using data binding (including those in dom-repeat and dom-if templates) are not added to the this.$ hash. The hash includes only statically created local DOM nodes (that is, the nodes defined in the element’s outermost template).

You will need to use this.$$('#yourElementId");

查看更多
甜甜的少女心
5楼-- · 2019-02-24 07:38

The responses above only work if your condition is true initially. Please see my answer to your initial question that lead to this one : https://stackoverflow.com/a/34137955/3085985

Not sure if you should mix in the .render-stuff from Dogs, but I still think the observer would be the right place for it as it otherwise does not work if condition is false initially.

查看更多
登录 后发表回答