DoK
DoK

Reputation: 871

Change type of paper-input programmatically

Is there a way to toggle the type of a paper-input programmatically? I have a paper-input element of type password and I want to change the type to text and vice versa.

This is the element what it looks like:

enter image description here

This is the implementation of the element:

<paper-input id="oldPassword"
             type="password"
             label="Old password"
             no-label-float required>
  <paper-icon-button suffix on-tap="toggleVisibility" 
                     icon$="[[setVisibility(passVisible)]]">
  </paper-icon-button>
</paper-input>

This is the JavaScript part:

toggleVisibility (e) {
  this.passVisible = !this.passVisible;
  e.currentTarget.type = this.passVisible ? 'text' : 'password';
}

The problem is that the type is set correctly but the paper-input element didn’t redraw itself.

Thanks for help!

Upvotes: 2

Views: 488

Answers (2)

Tomasz Pluskiewicz
Tomasz Pluskiewicz

Reputation: 3662

The answer by Tony does a great job answering your question.

I'd like to add to it by introducing some more declarative bindings into your element.

See below how I toggle the input type and icon by observing the icon button's active property and using it with computed bindings.

Polymer({
  is: 'some-form',
  getPasswordType: function (passVisible) {
    return passVisible ? 'text' : 'password';
  },
  getVisibilityIcon: function(isVisible) {
    return isVisible ? 'visibility' : 'visibility-off';
  }
})
<base href="https://polygit.org/components/">

<link href="polymer/polymer.html" rel="import">
<link href="paper-input/paper-input.html" rel="import">
<link href="paper-icon-button/paper-icon-button.html" rel="import">
<link href="iron-icons/iron-icons.html" rel="import">

<some-form></some-form>

<dom-module id="some-form">
  <template>
    <paper-input id="oldPassword"
                 type="[[getPasswordType(passVisible)]]"
                 label="Old password"
                 value="secret"
                 no-label-float required>
        <paper-icon-button suffix toggles 
                           active="{{passVisible}}"
                           icon$="[[getVisibilityIcon(passVisible)]]">
      </paper-icon-button>
    </paper-input>
  </template>
</dom-module>

Upvotes: 2

tony19
tony19

Reputation: 138326

In this case, e.currentTarget is actually <paper-icon-button>, not the <paper-input>.

You could reference the password input explicitly with this.$.oldPassword:

HTMLImports.whenReady(() => {
  "use strict";

  Polymer({
    is: 'x-foo',
    properties: {
      passVisible: {
        type: Boolean,
        value: false
      }
    },
    setVisibility(visible) {
      return visible ? 'icons:visibility' : 'icons:visibility-off';
    },
    toggleVisibility(e) {
      this.passVisible = !this.passVisible;
      this.$.oldPassword.type = this.passVisible ? 'text' : 'password';
    }
  });
});
<head>
  <base href="https://polygit.org/polymer+1.7.0/components/">
  <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
  <link rel="import" href="polymer/polymer.html">
  <link rel="import" href="iron-icons/iron-icons.html">
  <link rel="import" href="paper-input/paper-input.html">
  <link rel="import" href="paper-icon-button/paper-icon-button.html">
</head>
<body>
  <x-foo></x-foo>

  <dom-module id="x-foo">
    <template>
      <paper-input id="oldPassword"
             type="password"
             label="Old password"
             no-label-float
             required>
        <paper-icon-button suffix
                           on-tap="toggleVisibility" 
                           icon="[[setVisibility(passVisible)]]">
        </paper-icon-button>
      </paper-input>
    </template>
  </dom-module>
</body>

codepen

...or you could find the paper-input ancestor of e.currentTarget, which might make sense if you'd like to reuse the button handler for two of these paper-inputs in the same custom element (e.g., old and new password inputs):

HTMLImports.whenReady(() => {
  "use strict";

  Polymer({
    is: 'x-foo',
    properties: {
      passVisible: {
        type: Boolean,
        value: false
      }
    },
    setVisibility(visible) {
      return visible ? 'icons:visibility' : 'icons:visibility-off';
    },
    _getPaperInputAncestor(el) {
      while (el && el.localName !== 'paper-input') {
        el = el.parentElement;
      }
      return el;
    },
    toggleVisibility(e) {
      this.passVisible = !this.passVisible;
      const input = this._getPaperInputAncestor(e.currentTarget);
      input.type = this.passVisible ? 'text' : 'password';
    }
  });
});
<head>
  <base href="https://polygit.org/polymer+1.7.0/components/">
  <script src="webcomponentsjs/webcomponents-lite.min.js"></script>
  <link rel="import" href="polymer/polymer.html">
  <link rel="import" href="iron-icons/iron-icons.html">
  <link rel="import" href="paper-input/paper-input.html">
  <link rel="import" href="paper-icon-button/paper-icon-button.html">
</head>
<body>
  <x-foo></x-foo>

  <dom-module id="x-foo">
    <template>
      <paper-input id="oldPassword"
             type="password"
             label="Old password"
             no-label-float
             required>
        <paper-icon-button suffix
                           on-tap="toggleVisibility" 
                           icon="[[setVisibility(passVisible)]]">
        </paper-icon-button>
      </paper-input>
      <paper-input id="newPassword"
             type="password"
             label="New password"
             no-label-float
             required>
        <paper-icon-button suffix
                           on-tap="toggleVisibility" 
                           icon="[[setVisibility(passVisible)]]">
        </paper-icon-button>
      </paper-input>
    </template>
  </dom-module>
</body>

codepen

Upvotes: 2

Related Questions