Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VueJS select a specific element in dom

I wonder how I can select a specific element in the DOM using VueJS with our without jquery

In my component I have a method function that does this:

$(".u-loc input").focusin(function() {
    $(".u-loc-icon").addClass('blue-active');
});

The only problem is that its generated dynamic, so I could have 1 or 10 different which means I need to have a uniqe selector to each one.

So I have added :ref="'u-loc' + index"

Which means that I can now target the element using $(this.$refs['u-loc' + index]);

But I dont know how I can chain the selector to look something like this:

$(this.$refs['u-loc' + index]).('input').focusin(function() {
  $(this.$refs['u-loc' + index]).addClass('blue-active');
});

The problem is that I need to select the elements [input]

like image 388
Kiow Avatar asked Oct 24 '17 14:10

Kiow


People also ask

How do you access DOM elements in Vue?

If a ref attribute is added to an HTML element in your Vue template, you'll then be able to reference that element or even a child element in your Vue instance. You can also access the DOM element directly; it is a read-only attribute and returns an object.

How do I select HTML element in Vue?

querySelector in Vue We can use querySelector to select an HTML element that returns the first element within the document that matches a specified selector. It can be used to set, obtain, modify, or delete properties of the selected element in Vue.

How do I reference an element in Vue?

If we want to reference a DOM element, we can use the ref attribute in Vue. Vue can store references to DOM elements in a property called $ref . The first thing we have to do, is add a ref attribute to the element we want to reference in our Javascript.


3 Answers

You're making things very fragile with this approach. A quick fix for you would be to handle it like this.

<div class="input-container">
  <input @focusin="addParentClass" @focusout="removeParentClass">
</div>

Then have:

methods: {
  addParentClass (event) {
    event.target
      .closest('.input-container')
      .classList.add('blue-active')
  },
  removeParentClass (event) {
    event.target
      .closest('.input-container')
      .classList.add('blue-active')
  },
},

However, for the long term, you should look into breaking these into components. That way you can do something like:

<div :class="[containerClasses]">
  <input @focusout="isFocused = false" @focusin="isFocused = true">
</div>

Then have a computed property like:

computed: {
  containerClasses () {
    return {
      'input-container': true,
      'blue-active': this.isFocused,
    }
  },
},
like image 163
Bill Criswell Avatar answered Sep 20 '22 22:09

Bill Criswell


If I understand correctly what you are trying to accomplish then I think you're going wrong about it. I would add a vue.js event (focus) to all input elements:

<input @focus="onFocus" />

then I would define the onFocus method/event handler for the focus event on my Vue model:

methods: {
   onFocus: function (e) {
      var element = this.$el;
      var children = this.$el.childNodes;
   }
}

As you can see you can now get to the event envoking element via this.$el. Furthermore you can get to any child elements via this.$el.childNodes.

like image 37
Marko Avatar answered Sep 20 '22 22:09

Marko


Remember Vue is data driven so the view should reflect an underlying data model. In general you should not be injecting anything in to the DOM unless you have a specific reason to do so. In your case, what it looks like you want to di is highlight the input on focus by adding a class, so, we could have an array of input objects that have an active property:

new Vue({
  el: '#app',
  methods:{
    setActive(index){
        this.inputs[index].active = true;
    },
    removeActive(index){
        this.inputs[index].active = false;
    }
  },
  data: {
    inputs: [
        {value: 'foo', active: false},
        {value: 'bar', active: false}
    ]
  }
})

Now in your template you can use v-for to print all the inputs:

  <div v-for="(input, index) in inputs">
    <input v-model="input.value" @focusin="setActive(index)" @focusout="removeActive(index)" :class="{'blue-active' : input.active}"/> 
  </div>

You may notice that I'm attaching an event listener directly to each input (@focusin and @focusout), which calls a method that sets the active flag to true and false respectively for the given input (I've done that in a pretty verbose way for demonstrative purposes), I'm then using Vue's class binding to add and remove the blue-active class based on that flag.

And here's the final result: https://jsfiddle.net/mooxo19v/

like image 32
craig_h Avatar answered Sep 16 '22 22:09

craig_h