0

I have an app with some positions with possibilities to add each to "my library". By cklicking on "+" add menu is opened using js. The problem is that it does not always works, the variable with list lenght sometimes is not loaded so not every add menu is opening.

It gives error:

main.js:2 Uncaught TypeError: Cannot read properties of null (reading 'value')
    at main.js:2:55

My js code:

if (window.location.pathname === '/dashboard/') {
    let booksLen = document.getElementById("booksLen").value;  // takes number of positions
    for (let comp = 1; comp < booksLen; comp++) {
        let bookAddButton = document.getElementById(`add-btn-${comp}`)
        let bookAddComp = document.getElementById(`add-comp-${comp}`)
        bookAddButton.addEventListener('click', () => {
            if (bookAddComp.classList.contains('d-none') === false) {
                bookAddComp.classList.toggle('d-none')
            } else {

                // disable all previously opened submit forms and error msg
                for (let compDisable = 1; compDisable < 5; compDisable++) {
                    let bookAddCompDisable = document.getElementById(`add-comp-${compDisable}`)
                    let errMsgDisable = document.getElementById(`err-msg-${comp}`)
                    if (bookAddCompDisable.classList.contains('d-none') === false) {
                        bookAddCompDisable.classList.toggle('d-none')
                    }
                    if (errMsgDisable.classList.contains('d-none') === false) {
                        errMsgDisable.classList.toggle(('d-none'))
                    }
                }
                // open only one submit form at a time
                bookAddComp.classList.toggle('d-none')
            }

        })

        let submitButton = document.getElementById(`submit-button-${comp}`)

        // show error msg
        submitButton.addEventListener('click', e => {
            let bookInput = document.getElementById(`input-${comp}`).value
            let errMsg = document.getElementById(`err-msg-${comp}`)
            if (bookInput === "") {
                errMsg.classList.remove('d-none')
                e.preventDefault()
            }
        })
    }
}

I pass the variable like this:

<input type="hidden" id="booksLen" name="booksLen" value="{{ books_len }}">

also in my base.html i use:

<script src="{% static './js/main.js' %}" async defer></script>
class BooksAvailability(View):
    # displays books related to libraries filtered for proper user. Only records desired by user
    def get(self, request):
        user = request.user
        libraries = models.Libraries.objects.all()
        books = models.Books.objects.filter(user=user.id)
        status = models.BooksLibraries.objects.all()

        books_len = len(books) + 1 # passes variable for js purpose. Book add to my library feature
        return render(request, 'library/dashboard.html',
                      context={'libraries': libraries, 'status': status, 'books': books, 'books_len':books_len})

Why does it not always work as it should? When the variable loads corectly it all works as I desire.

I tried to not pass the lenght variable but count positions in js but it didn't work also.

Jumper
  • 1
  • 1
  • fyi it is "length" – epascarello Mar 21 '23 at 12:55
  • So the problem is the python and what ever you are using to output the variable to the page is not outputting the correct number? – epascarello Mar 21 '23 at 12:58
  • @epascarello when I first get on the page it gives "Uncaught TypeError: Cannot read properties of null (reading 'value') at main.js:2:55" usually after I refresh it works – Jumper Mar 21 '23 at 13:04
  • So that error says it can not find the input. Seems odd since you use defer. https://stackoverflow.com/questions/14028959/why-does-jquery-or-a-dom-method-such-as-getelementbyid-not-find-the-element – epascarello Mar 21 '23 at 13:05
  • I tried DOMContentLoaded and the result was the same but 'Window: load event' solved the problem – Jumper Mar 21 '23 at 14:04

0 Answers0