0
votes

I would like to show and hide an icon on my input based on the prop type.

If the type is password it will show the icon to make the password visible/hidden; if the type is not password it should hide the icon changing the v-show to false.

Here is the HTML with a v-show showPwIcon to make the icon visible

<input
  ref="textField"
  v-model="textField"
  :placeholder="placeholder"
  :type="type"
>
<span v-show="showPwIcon" @click="switchVisibility">
  <i :class="[pwIcon ? 'ri-eye-line' : 'ri-eye-off-line']"></i>
</span>

And here the JS, without the CSS for example purpose only, with the v-show showPwIcon set to false by default:

export default {
  props:{
    placeholder: {
      type: String,
      value: ''
    },
    type: {
      type: String,
      value: '',
      required: true
    }
  },
  data() {
    return {
      textField: '',
      showPwIcon: false,
      pwIcon: true
    }
  },
  watch: {
    type: function (password) {
      const inputType = this.$refs.textField.type
      if (inputType === 'password') {
      this.showPwIcon = true
    } else {
        this.showPwIcon = false
      }
    }
  },
  methods: {
    switchVisibility() {
      this.$emit('input', {
        type: this.$refs.textField.type = this.$refs.textField.type === 'password' ? 'text' : 'password'
      })
      if (this.$refs.textField.type === 'password') {
        this.pwIcon = true
      } else {
        this.pwIcon = false
      }
    }
  }
}

With the current code I'm having this issue:

With type text it's not showing the icon

<text-field-icon
  placeholder="Placeholder here"
  type="text"
/>

The type is password but the v-show is not true.

<text-field-icon
  placeholder="Placeholder here"
  type="password"
/>

I am trying to get this work watching the prop type on the input but I'm not able to get the input type with this.$refs.textField.type

Sample code https://codesandbox.io/s/vue-tailwind-template-dteq4

Any thoughts?

2
Please create a small demo for this using codesandbox.io to show the issue happening. - palaѕн
updated with code sample - Fabio Zanchi

2 Answers

1
votes

We don't' need watcher or $refs to achieve this.

Note that $refs are not reactive

<input
  v-model="textField"
  :placeholder="placeholder"
  :type="inputType"
>
<span v-show="showPwIcon" @click="switchVisibility">
  <i :class="[pwIcon ? 'ri-eye-line' : 'ri-eye-off-line']"></i>
</span>
export default {
  props: {
    placeholder: {
      type: String,
      value: ""
    },
    type: {
      type: String,
      value: "",
      required: true
    }
  },
  data() {
    return {
      textField: "",
      pwIcon: false,
      inputType: this.type
    };
  },
  computed: {
    showPwIcon() {
      return this.type === "password";
    }
  },
  methods: {
    switchVisibility() {
      this.inputType = this.inputType === "password" ? "text" : "password";
      this.$emit("input", {
        type: this.inputType
      });
      this.pwIcon = this.inputType === "text";
      console.log(this.inputType, this.pwIcon);
    }
  }
};
0
votes

You do not need a complicated watcher for this. If you think about UI = Function(State), then you should just rely on using type prop instead of reading value of type from actual input Element - this.$refs.textField.type. Further, note that $refs is not reactive.

The simple solution would be

<input
  v-model="textField"
  :placeholder="placeholder"
  :type="(showPwIcon && !pwIcon) ? 'text' : type">

<span v-show="showPwIcon" @click="switchVisibility">
  <i :class="[pwIcon ? 'ri-eye-line' : 'ri-eye-off-line']"></i>
</span>
export default {

  // Props and data declaration...

  watch: {
    type: function (newVal) {
      if (newVal === 'password') {
        this.showPwIcon = true

        // Initially, set password visibility to false
        this.pwIcon = true
      } else {
        this.showPwIcon = false
      }
    }
  },

  methods: {
    switchVisibility() {

      // Toggle Visibility
      this.pwIcon = !this.pwIcon;

      this.$emit('input', {
        type: this.pwIcon ? 'text' : 'password'
      })
    }
  }
}

Remember, your source of truth is your component instance and not the DOM. Reading from $refs is like you are creating a second source of truth. $refs is designed for non-Vue compatible libraries where you need to talk to actual DOM. Few examples are, Charting libraries, Video players, etc.