Search code examples
checkboxpolymerpolymer-1.0togglebuttonmultiple-instances

Custom created toggle switch in Polymer1.0 doesn't work for more than one instance


Imported Polymer (1.0.0) and created a custom control which toggles and display text based on toggle value whether it is enabled or disabled. When I use this element more than once the text is not changing properly. Only for the first instance, it works, the remaining instance text is not changing it remains as Disabled in both states of the toggle switch.

<link rel="import" href="../bower_components/polymer/polymer.html" />

<dom-module id="toggle-element">

  <style>
    #labelDisplay {
      height: 14px;
      width: 43px;
      color: #4d4d4d;
      font-family: Roboto;
      font-size: 12px;
      line-height: 14px;
      margin-left: 6px;
    }
    .switch {
      position: relative;
      display: inline-block;
      width: 41px;
      height: 16px;
    }

    .switch input {
      opacity: 0;
      width: 0;
      height: 0;
    }

    .slider {
      position: absolute;
      cursor: pointer;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: #cacaca;
      -webkit-transition: 0.4s;
      transition: 0.4s;
    }

    .slider:before {
      /* Slider Round */
      position: absolute;
      content: "";
      height: 12.5px;
      width: 12.5px;
      top: 1px;
      background-color: white;
      -webkit-transition: 0.2s;
      transition: 0.2s;
    }

    input:checked + .slider {
      background-color: #329b46;
    }

    input:focus + .slider {
      box-shadow: 0 0 1px #329b46;
    }

    input:checked + .slider:before {
      -webkit-transform: translateX(26px);
      -ms-transform: translateX(26px);
      transform: translateX(26px);
    }

    /* Rounded sliders */
    .slider.round {
      border-radius: 40px;
    }

    .slider.round:before {
      border-radius: 50%;
    }
  </style>
  <template>
    <label class="switch">
      <input type="checkbox" id="checkInput" on-change="setValue" />
      <span class="slider round"></span>
    </label>
    <span id="labelDisplay">Disabled</span>
  </template>

Below is the custom element scripting file which handles text display (Enabled/Disabled) based on toggle switch value.

  <script>
    Polymer({
      is: "toggle-element",
      properties: {
        status: String,
      },
      setValue: function () {
        //Changes checkbox label based on checkbox value

        // Get status of toggle switch (Id : status) &
        // Set label text value respectively (Id : value)
        [
          document.getElementById("labelDisplay").innerHTML,
          this.status,
        ] = document.getElementById("checkInput").checked
          ? ["Enabled", "true"]
          : ["Disabled", "false"];
      },
    });
  </script>
</dom-module>

Solution

  • The problem is with using a function to update string 'Enabled/Disabled' in span tag. I think that process is shared by all instances instead of having its own.

    So I changed the approach by using dom-if

    <link rel="import" href="../bower_components/polymer/polymer.html" />
    
    <dom-module id="toggle-element">
      <style>
        #labelDisplay {
          height: 14px;
          width: 43px;
          color: #4d4d4d;
          font-family: Roboto;
          font-size: 12px;
          line-height: 14px;
          margin-left: 6px;
        }
        .switch {
          position: relative;
          display: inline-block;
          width: 41px;
          height: 16px;
        }
    
        .switch input {
          opacity: 0;
          width: 0;
          height: 0;
        }
    
        .slider {
          position: absolute;
          cursor: pointer;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background-color: #cacaca;
          -webkit-transition: 0.4s;
          transition: 0.4s;
        }
    
        .slider:before {
          /* Slider Round */
          position: absolute;
          content: "";
          height: 12.5px;
          width: 12.5px;
          top: 1px;
          background-color: white;
          -webkit-transition: 0.2s;
          transition: 0.2s;
        }
    
        input:checked + .slider {
          background-color: #329b46;
        }
    
        input:focus + .slider {
          box-shadow: 0 0 1px #329b46;
        }
    
        input:checked + .slider:before {
          -webkit-transform: translateX(26px);
          -ms-transform: translateX(26px);
          transform: translateX(26px);
        }
    
        /* Rounded sliders */
        .slider.round {
          border-radius: 40px;
        }
    
        .slider.round:before {
          border-radius: 50%;
        }
      </style>
    
    
      <template>
        <label class="switch">
          <input type="checkbox" id="checkInput" checked="{{status::input}}" />
          <span class="slider round"></span>
        </label>
        <template is="dom-if" if="[[!status]]"
          ><span id="labelDisplay">Disabled</span></template
        >
        <template is="dom-if" if="[[status]]"
          ><span id="labelDisplay">Enabled</span></template
        >
      </template>
    
      <script>
        Polymer({
          is: "toggle-element",
          properties: {
            status: {
              value: false,
              type: Boolean,
            },
          },
        });
      </script>
    </dom-module>
    

    In the above-mentioned approach, each instance will have its own template in displaying its state (Enabled/Disabled). Perks of having template

    Separated template section alone for easy understanding.

    <template>
        <label class="switch">
          <input type="checkbox" id="checkInput" checked="{{status::input}}" />
          <span class="slider round"></span>
        </label>
        <template is="dom-if" if="[[!status]]"
          ><span id="labelDisplay">Disabled</span></template
        >
        <template is="dom-if" if="[[status]]"
          ><span id="labelDisplay">Enabled</span></template
        >
    </template>