Vue.js accessing element via function

Viewed 352

I need to add class to label element when I focus on an input element which is below the label. My current solution is this:

HTML:

<label for="formProductId" ref="productIdLabel" class="form-element-title">Product ID</label>
<input id="formProductId" @blur="toggleFocus('productIdLabel', false)" @focus="toggleFocus('productIdLabel', true)" v-model="filterValues.productId" :name="filterOptions.productId === true ? 'productId' : false" type="text">

JS:

toggleFocus(ref: string, enable: boolean) {
    if (enable) {
        (this.$refs[ref] as HTMLElement).classList.add("js-focused");
    } else {
        (this.$refs[ref] as HTMLElement).classList.remove("js-focused");
    }
}

I would like to remove the ref attribute and toggle js-focused class completely by the selected element itself. How do I select the closest label element and edit it's class?

2 Answers

You can use previousElementSibling with event.target.

Example:

new Vue({
  el: '#app',
  methods: {
    toggleLabelColor(event) {
      event.target.previousElementSibling.classList.toggle('input-focused')
    }
  }
})
input {
  display: block;
}

.input-focused {
  color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <label>I turn green when focused.</label>
  <input @focus="toggleLabelColor" @blur="toggleLabelColor">

  <label>I turn green when focused.</label>
  <input @focus="toggleLabelColor" @blur="toggleLabelColor">

  <label>I turn green when focused.</label>
  <input @focus="toggleLabelColor" @blur="toggleLabelColor">
</div>

A better approach is to use dynamic class. See this example:

new Vue({
  el: '#app',
  data: {
    productIdLabel: false
  }
})
.js-focused {
  background-color: lightblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id='app'>
  <label for="formProductId" class="form-element-title" :class="{'js-focused': productIdLabel == true}">Product ID</label>
  <input id="formProductId" @blur="productIdLabel = false" @focus="productIdLabel = true" type="text">
</div>

Use with component and multiple form inputs:

Vue.component("form-label", {
  template: `<div>
   <label :for="info.id" class="form-element-title" :class="{'js-focused': isFocused == true}">{{info.label}}</label>
   <input :id="info.id" @blur="isFocused = false" @focus="isFocused = true" type="text">
 </div>`,
 props: ["info"],
 data: function(){
  return {
   isFocused: false
  }
 }
})
new Vue({
  el: '#app',
  data: {
    form: [{
      label: "Product Id",
      id: "formProductId"
    }, {
      label: "Another Element",
      id: "anoterId"
    }, {
      label: "Third Element",
      id: "thirdId"
    }]
  }
})
.js-focused {
  background-color: lightblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id='app'>
  <form-label v-for='el in form' :info='el'></form-label>
</div>

Related