dynamic classes on polymer 1.0 elements
Asked Answered
M

2

6

I created this component to demonstrate my question. This component works in chrome and firefox, as expected. But if I write this.$.wrapper.setAttribute('class','blue'); instead of this.$.wrapper.setAttribute('class','blue style-scope poly-test'); it stops working in firefox.

Is this the preferred way to change classes on shadow dom elements inside an event handler, or am I doing something accidentally right, that might break in a future version?

Also, why do I have to specify style-scope and my element name as a class manually for firefox?

<link rel="import" href="../js/bower_components/polymer/polymer.html">
<dom-module id="poly-test">
  <style>
    .blue { border: 10px solid blue; }
    .red  { border: 10px solid red; }
    #wrapper { font-weight: bold; font-size: 42px; }
  </style>
  <template>
    <div id="wrapper" class="red"><content></content></div>
  </template>
</dom-module>
<script>
  Polymer({
    is: 'poly-test',
    properties: {'blue': { type: 'Boolean', value: false }},
    listeners: { 'click': 'clickHandler' },
    clickHandler: function () {
      this.blue = !this.blue;
      if (this.blue) {
        this.$.wrapper.setAttribute('class','blue style-scope poly-test');
      } else {
        this.$.wrapper.setAttribute('class','red  style-scope poly-test');
      }
      this.updateStyles();
    }
  });
</script>
Masonmasonic answered 11/7, 2015 at 23:36 Comment(0)
A
9

The idea of web components is to make the web as declarative as possible. In that spirit, the Polymer-way of implementing dynamic classes should be

Declarative approach: (https://www.polymer-project.org/1.0/docs/devguide/data-binding.html#native-binding)

...
<dom-module id="poly-test">
  ...
  <template>
    <!-- handle dynamic classes declaratively -->
    <div class$="{{computeClass(isBlue)}}">
      <content></content>
    </div>
  </template>
</dom-module>
<script>
  Polymer({
    is: 'poly-test',
    properties: {
      'isBlue': { type: Boolean, value: false }
    },
    listeners: { 'click': 'clickHandler' },
    clickHandler: function () {
      this.isBlue = !this.isBlue;
    },
    computeClass: function (f) {
      return f ? "blue" : "red";
    }
  });
</script>

style-scope is used by the framework when upgrading elements and stamping nodes into DOM (under shady behaviour I believe), and I don't think we are meant to touch it.

If you really wish to handle imperatively, I'll recommend using the Polymer API's toggleClass() method.

Imperative approach: (http://polymer.github.io/polymer/)

...
<dom-module id="poly-test">
  ...
  <template>
    <div id="wrapper" class="red"><content></content></div>
  </template>
</dom-module>
<script>
  Polymer({
    is: 'poly-test',
    properties: {
      'isBlue': { type: Boolean, value: false }
    },
    listeners: { 'click': 'clickHandler' },
    clickHandler: function () {
      this.isBlue = !this.isBlue;
      this.toggleClass("blue", this.isBlue, this.$.wrapper);
      this.toggleClass("red", !this.isBlue, this.$.wrapper);
    }
  });
</script>
Agonized answered 12/7, 2015 at 7:29 Comment(0)
A
2

Use the classList property to manage classes:

<link rel="import" href="../js/bower_components/polymer/polymer.html">
<dom-module id="poly-test">
  <style>
    .blue { border: 10px solid blue; }
    .red  { border: 10px solid red; }
    #wrapper { font-weight: bold; font-size: 42px; }
  </style>
  <template>
    <div id="wrapper" class="red"><content></content></div>
  </template>
</dom-module>
<script>
  Polymer({
    is: 'poly-test',
    properties: {'blue': { type: 'Boolean', value: false }},
    listeners: { 'click': 'clickHandler' },
    clickHandler: function () {
      this.blue = !this.blue;
      this.$.wrapper.classList.toggle('blue', this.blue);
      this.$.wrapper.classList.toggle('red', !this.blue)
    }
  });
</script>

More information on classList: https://developer.mozilla.org/en-US/docs/Web/API/Element/classList

Academicism answered 12/7, 2015 at 1:31 Comment(1)
I should mention, that I tested all three answers, this is a working solution too, but I'm accepting zerodevx's answer for pointing out the declarative approach.Masonmasonic

© 2022 - 2024 — McMap. All rights reserved.