Polymer data change doesn't reflect

2019-07-08 08:24发布

问题:

I'm trying to hide/unhide a UI element with a button in Polymer, but it doesn't work. I have the button and the element:

<button id="runPredictionButton">
    <i>Button text</i>
</button>
<px-card 
hidden$="{{hide}}">    
//...content here
</px-card>
<div class="output"></div>          

And I defined the property and the event listener, too:

  <script>
    Polymer({
      is: 'custom-view',
      properties: {
        hide: {
          type: Boolean,
          value: false 
        },
      },
    ready: function() {
      var self = this;
      this.$.runPredictionButton.addEventListener('click', function() {
        if (some_conditon == true) {
          filerootdiv.querySelector('.output').innerHTML = 'Is true';          
          this.hide = true
          console.log("This hide should be true:" + this.hide);
        } 
        else {
          filerootdiv.querySelector('.output').innerHTML = 'Is false';          
          this.hide = false
          console.log("This hide should be false:" + this.hide);
        }
      });
    }
  });      
  </script>

I'm sure some_conditon works, because the content of the .output element does change, however the px-card element does not get hidden/unhidden at all. Also, on the console I can see that this.hide HAS been changed to the required value, but the element stays hidden no matter what. Is there something I need to do/automatically force the content to update? Why does this not work? How can I make sure to hide the px-card element by changing the hide variable?

回答1:

good question. So, first of all I would like to highlight, that current JS code of that Polymer component it's not actually "very Polymer", so you are interacting with DOM in very "jQuery way", instead of use all the benefits of Polymer library.

How I would suggest to rewrite that code:

<button on-tap="hidePxCard">
    <i>Button text</i>
</button>
<px-card
hidden$="[[hide]]">
<!-- ...content here -->
</px-card>
<div class="output"></div>

So, here we've added 1) on-tap event hander hidePxCard 2) switched from two-way biding to one-way for [[hide]] via square brackets, so, there is no reason to use two-way binding.

Then, let's adjust js part:

<script>
    Polymer({
        is: 'custom-view',
        properties: {
            hide: {
                type: Boolean,
                value: false
            }
        },
        hidePxCard: function() {
            this.set('hide', !this.hide);
        }
    });
</script>

Could you see, how clean code looks now? We just setup one property on every hidePxCard call. Our goal is, that we need to manipulate with Polymer properties, which bind to html attributes, and not manipulate DOM directly. So, your element is data driven now.

Also, I'm assuming that there is some CSS code is present to hide something when [hidden] attribute is present on the element.

It could be done inside px-card element via:

<style>
    :host{
        display: block;
    }
    :host[hidden]{
        display: none;
    }
</style>

or been setup in somewhere as global style across the app (page).



回答2:

Maybe a CSS rule is preventing it from being hidden?

Make sure the thing you want to hide is styled so that the browser knows what to do when hidden is true (i.e., the browser should set display to none). E.g.:

<style>
  :host{
    display: block;
  }
  :host[hidden]{
    display: none;
  }
</style>

To see whether this is in fact the cause of your issue, you can check this info:

getComputedStyle(elementToHide).getPropertyValue("display"); 

This code sample shows the above in action.

Web Components Best Practices has more info on using the :host selector.