johnnyrocket33
johnnyrocket33

Reputation: 131

document.querySelector causing errors on other methods when called

My apologies for the stupid question, but I am trying to change the name of a button upon uploading a file. My code to change it is this, via TypeScript:

    const i = (document.querySelector('label') as any).innerText = filename;

The code above, inside the fileName method, changes the "Upload Project File" text into the name of whatever file that is uploaded.

    <div class="row">
      <div class="clg6 cmd8 csm10 cxs12" v-if="this.projectFile">
        <button 
          class="button primary outline medium upload">
          <label>
            <input 
            type="file"
            name="projectFile"
            id="fileName"
            accept=".xls, .xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel" 
            v-on:change="validateFileType(); hashContentMD5(); fileName; getPresignedURL()"/>
              <i class="fas fa-cloud-upload"></i> 
              Upload Project File
          </label>
        </button>
      </div>
    </div>

And it works. However, upon change, it brings up errors in my other methods when they're called, such as this:

const file = (document.getElementById('fileName')as any).files[0]

The error that shows up is

Uncaught (in promise) TypeError: Cannot read properties of null (reading 'files')

Removing the document.querySelector removes the error. This is the first time that I've encountered this. How can I fix it?

Upvotes: 0

Views: 94

Answers (2)

Janos Vinceller
Janos Vinceller

Reputation: 1266

Problems:

You put your input inside the label tag. I learned this is okay.

  1. Why using a button outside the whole label and input tags? I don't understand what your intention was with that.
  2. You replace the inside of the label tag by a text node (containing the file name). Through your replacement you delete your input field out of the DOM. See querySelector line in your code.
  3. After having replaced the input field, there is no fileName on the page anymore, so it getElementById results in null.

Solution:

  1. (optionally) I'd delete the button tag and only keep the inside of it.
  2. Don't operate on that label and don't try to overwrite the value of a file input field
  3. By not removing the input field anymore, you can access it and read out the file name

See my example here: https://stackblitz.com/edit/js-fdxxnf

Upvotes: 2

Nikola Pavicevic
Nikola Pavicevic

Reputation: 23490

You can try with ref:

new Vue({
  el: '#demo',
  data() {
    return {
      projectFile: true
    }
  },
  methods: {
    changeLbl() {
      this.$refs.lab.innerText = 'filename'
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
  <div class="row">
      <div class="clg6 cmd8 csm10 cxs12" v-if="projectFile">
        <button 
          class="button primary outline medium upload">
          <label ref="lab">
            <input 
            type="file"
            name="projectFile"
            id="fileName"
            accept=".xls, .xlsx, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel" 
            v-on:change="changeLbl"/>
              <i class="fas fa-cloud-upload"></i> 
              Upload Project File
          </label>
        </button>
      </div>
  </div>
</div>

Upvotes: 1

Related Questions