1

I have two components for editing JSON objects. And i have a button that switches between these two. Here is the html code:

<v-btn @click="switchConfigClicked">Switch config</v-btn>
<h4 class="switchButtonInfo">Switch between editor/plain-text</h4>
<v-btn class="switchEditButton" @click="switchEditButtonClicked">Switch Editor</v-btn>
<div class= "editorComponents">
  <div v-if="showEditComponents" class="editor">
    <div v-if="showJsonEditor">
      <JsonEditor is-edit="true" v-model="editedConfig" ></JsonEditor>
    </div>
    <div v-if="showTextEditor">
      <textarea id="myTextArea" cols=75 rows=100></textarea>
    </div>
  </div>

//Javascript code

switchEditButtonClicked: function(){

  this.showTextEditor = !this.showTextEditor;
  this.showJsonEditor = !this.showJsonEditor;

  if (this.showTextEditor) {

    this.editedConfig = JSON.stringify({"hello":"test"}, undefined, 4);

    document.getElementById('myTextArea').innerHTML = this.editedConfig;

  }
  else{
    //this.editedConfig = JSON.parse(this.edite)
  }

},

Start value for showJsonEditor = true, showTextEditor = false gives me the error:

Cannot set property 'innerHTML' of null", Vue

i tried setting the the code like below

window.onload = function() {
    // all of your code goes in here
    // it runs after the DOM is built
}

No error is shown but also no text is shown.

Test case

i commented out these two lines from switchConfigClicked:

//this.showTextEditor = !this.showTextEditor;
//this.showJsonEditor = !this.showJsonEditor;

and reversed the boolean start values for showJsonEditor = false, showTextEditor = true

Result

Text is shown in the textEditor with no errors..

Conclusion

I have a feeling that it has to do with my v-if, when showTextEditor is set to false and then changed to true maybe we are trying to put the text in before the new DOM is created? Not really sure why and how to fix this..

Timo Cengiz
  • 3,367
  • 4
  • 23
  • 45
  • This means that `document.getElementById('myTextArea')` does not find an element with the ID `myTextArea` in the DOM at the time it is called. Maybe Vue has not entered the update circle. But using `document.getElementById('myTextArea').innerHTML = ...` in Vue is something you should not do anyway. – t.niese Jan 22 '19 at 10:12

2 Answers2

3

The textarea is not yet available/rendered at this point (deferred by v-if), try querying for it inside Vue.nextTick.

Defer the callback to be executed after the next DOM update cycle. Use it immediately after you’ve changed some data to wait for the DOM update.

switchEditButtonClicked: function () {
  this.showTextEditor = !this.showTextEditor;
  this.showJsonEditor = !this.showJsonEditor;

  if (this.showTextEditor) {
    this.editedConfig = JSON.stringify({
        "hello": "test"
      }, undefined, 4);

    Vue.nextTick(() => {
      // Or better yet use a `ref`
      document.getElementById('myTextArea').innerHTML = this.editedConfig;
    });

  } else {
    //this.editedConfig = JSON.parse(this.edite)
  }

}
tony19
  • 125,647
  • 18
  • 229
  • 307
Yom T.
  • 8,760
  • 2
  • 32
  • 49
  • Just a quick question. I am using the promise version of nextTick so i am refering to the same vue instance when using `this` however i am getting: `uncaught (in promise) TypeError: Cannot read property` when trying to do a console.log on my `this` variable – Timo Cengiz Jan 22 '19 at 13:07
  • @TimoCengiz If you're using it with [arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) you shouldn't get that type error. Can you post in here how you are using it real quick? Or maybe edit your post. – Yom T. Jan 22 '19 at 13:11
  • No problem, glad you sorted it out! :) – Yom T. Jan 22 '19 at 13:15
0

Cannot set property 'innerHTML' of null", Vue

This means that the line document.getElementById('myTextArea').innerHTML fails and the problem is with the lookup - document.getElementById('myTextArea') returns nothing, which clarifies the error message - the lookup by ID results in null, and you try to set the innerHTML of that.

You do have an element with myTextArea ID, so the reason for that is that the element is not present when the JavaScript code runs.

This also explains why setting the code to run with window.onload doesn't show the error - this will set it to execute after the page has been fully rendered, so the DOM element will exist and you'd be able to fetch it.

The reason why you get no text then is because you are adding it the wrong way. Instead of .innerHTML you should set the .value property

document.getElementById('myTextArea').value = this.editedConfig;
VLAZ
  • 26,331
  • 9
  • 49
  • 67
  • @TimoCengiz you need to have both the code in `window.onload` and to be setting the `.value` property. – VLAZ Jan 22 '19 at 10:20
  • Same as described, no error now but still no text is updated. empty textarea :( – Timo Cengiz Jan 22 '19 at 10:21
  • @TimoCengiz then, the only thing I can think of is that there is another update to the text area that happens after this. I'm not familiar enough with Vue - perhaps what you have is the wrong setup and you should be doing the update in a different way? – VLAZ Jan 22 '19 at 10:23
  • Going back one step.. What do you mean with ´you need to have both the code´ what is ´code´ in this context? i only put the ´.value´ row in ´window.onload´ – Timo Cengiz Jan 22 '19 at 10:26
  • If you only put `document.getElementById('myTextArea').value = this.editedConfig;` in `window.onload`, then you wouldn't have the value of `this.editedConfig` – VLAZ Jan 22 '19 at 10:27
  • Put all the code in window.onload still did not work. @jom's answer did the trick. Thank you for the help – Timo Cengiz Jan 22 '19 at 10:34