Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js trying to get DOM element by ID in computed returns null

I am wondering if it is posible to get elements by their id in Vue.js from a computed function. It is a silly question but for some reason it is giving me null as a response when I try to log this condition.

Let's say these are html tags:

<button id="dice1" class="revol"></button>
<button id="dice2" class="revol"></button>

then in one of my computed methods I try to access both ids

computed: {
  roll(){
    document.getElementById("dice1").className += "dic1";
    document.getElementById("dice2").className += "dic2";

    ...some code 
  }
}

Due to the error I checked in the created hook what was going on and realize that the document.getElementById of any id returns null

created() {
  console.log(document.getElementById("dice1"));
  console.log(document.getElementById("dice1"));
},

Also instead of referring straight to the DOM element I initialize variables and assigning the elementsById to them, but the results are the same

rollDice() {
  var  diceFirst= document.getElementById("dice1");
  var diceSecond= document.getElementById("dice2")
  
  diceFirst.className += "dic1";
  diceSecond.className += "dic2";

  ....some code
}

How can I improve this situation? Thanks in advance!

like image 740
Enrique GF Avatar asked Jul 14 '20 10:07

Enrique GF


2 Answers

Stemming from Decade Moon's comment, Vue doesn't like it when you manually manipulate the DOM (well, actually, Vue doesn't care, but it's bad practice since detaches your data from its representation in the DOM, which is not what you want when making a datadriven app). Instead, whenever you want to set the class of an element, do it with data (or with a computed property).

Your DOM should be representing your data, not the other way around.

new Vue({
  el: '#app',
  data: {
    class1: 'revol',
    class2: 'revol'
  },
  methods: {
    rollDice: function() {
      class1 += 'dic1';
      class2 += 'dic2';
      
      // ... some code
    }
  }
});
<div id="app">
  <button id="dice1" v-bind:class="class1">Dice 1</button>
  <button id="dice2" v-bind:class="class2">Dice 2</button>
</div>

This rollDice function does exactly the same thing as yours—it adds a new class to the buttons—but with a data-driven approach instead of trying to manipulate the DOM. In this case, the two buttons represent the data in class1 and class2, instead of having them decoupled.

like image 62
matthew-e-brown Avatar answered Oct 06 '22 01:10

matthew-e-brown


The elements in the DOM are only available in the mounted hook. In created, the DOM elements are not rendered yet so you're unable to get them.

You can also use $ref to get the element from the DOM.

  <input type="text" ref="textbox" />

In the script, you can access this element using

  let tBox = this.$ref.textbox;

tBox will hold the input DOM element.

In the snippet below you can see how to get the element by id.

new Vue({
  el: "#app",
  mounted() {
    document.getElementById('header').textContent = 'New Text'
  }
})
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

<div id="app">
  <h1 id="header">Component Text</h1>
</div>
like image 39
Stark Buttowski Avatar answered Oct 06 '22 00:10

Stark Buttowski