Discussion:
getElementById zwraca null
(Wiadomość utworzona zbyt dawno temu. Odpowiedź niemożliwa.)
Jivanmukta
2018-11-11 20:49:18 UTC
Permalink
Napisałem:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="pl">
<head>
...
<script type="text/javascript">
$(document).ready(function () {
...
// tu przypisania funkcji submitForm i animateMainTitle
...
});
</script>
</head>
...
<body>
...
<table id="top" border="0">
<caption><h1 id="main_title">...</h1></caption>
...
</table>
...
<form action="http://localhost/~robert/announcement/insert"
id="announcement" name="announcement" enctype="multipart/form-data"
method="post" accept-charset="utf-8">
...
<div id="property_pictures_field">
...
<input multiple='multiple' type='file' id='property_pictures'
name='property_pictures[]' class='multi'
accept='gif|jpg|jpeg|jpe|bmp|png|gif87|gif89a|mpg|mpeg|mpe|mov|avi|wmv|vob|ogm|ogv'
value='Wybierz plik' tabindex='61'> </div>
...
</div>
...
</form>
...
</body>
</html>

Czasami mam błędy JavaScript w konsoli przeglądarki (testowałem pod
FireFoxem, Operą, Chrome):

function submitForm() {
...
alert(document.getElementById("property_pictures_field")); // OK
var pp = document.getElementById("property_pictures").value; //
CZASAMI BŁĄD: getElementById JEST null
...
}

function animateMainTitle() {
...
mainTitle = document.getElementById("main_title").innerHTML; //
CZASAMI BŁĄD: getElementById JEST null
...
}

Pliki .html, .css, .js przechodzą pomyślnie walidację.
Nie mam innego elementu o id='property_pictures' ani innego o
id="main_title", literówki w id nie ma.
DOM dokument jest załadowany w chwili wywołania.
Nie usuwam elementów property_pictures ani main_title przy pomocy
JavaScript.
Przejrzałem w Google strony "getElementById returns null" i nie
znalazłem przyczyny mojego błędu.
Prosiłbym o podpowiedź co robię źle.
Marek S
2018-11-18 17:56:09 UTC
Permalink
Post by Jivanmukta
Pliki .html, .css, .js przechodzą pomyślnie walidację.
Nie mam innego elementu o id='property_pictures' ani innego o
id="main_title", literówki w id nie ma.
DOM dokument jest załadowany w chwili wywołania.
Nie usuwam elementów property_pictures ani main_title przy pomocy
JavaScript.
Przejrzałem w Google strony "getElementById returns null" i nie
znalazłem przyczyny mojego błędu.
Prosiłbym o podpowiedź co robię źle.
Taki błąd powstaje raczej tylko w przypadku gdy DOM nie jest w pełni
załadowany. Nic innego mi do głowy nie przychodzi. A kiedy może się tak
dziać? Z praktyki webdewelopera najczęściej to:

1. Jakiś skrypt zmienia / przebudowuje strukturę dokumentu. Również może
to być refresh.

2. Strona ładuje się i następuje chwilę potem przekierowanie do jej
samej (3xx). Sprawdź po stronie sieci w narzędziach czy nie ma czegoś
takiego.

Ustaw też w na początku funkcji animateMainTitle jakiś log do konsoli by
sprawdzić czy nie następuje podwójne wywołanie w samym JS.

3. Ponadto z nazwy w/w funkcji wnioskuję iż naruszasz strukturę DOM by
coś zanimować. Nie wiem jak konkretnie animujesz więc tylko zgaduję.
Jeśli np. używasz innerHTML gdzieś dalej do zapisu, to wtedy takie cuda
mogą się dziać. Nie należy używać do tego celu innerHTML bo jest
strasznie wolne gdyż wymusza odświeżanie _CAŁEJ_ struktury DOM. Wtedy
okresowo możesz tracić dostęp do DOM mimo iż pozornie wydaje Ci się, że
nic się w niej nie zmienia. To dość częsty błąd początkujących
programistów JS a i zaawansowani czasem też o tym nie wiedzą.
--
Pozdrawiam,
Marek
Jivanmukta
2018-11-19 07:54:14 UTC
Permalink
Post by Marek S
3. Ponadto z nazwy w/w funkcji wnioskuję iż naruszasz strukturę DOM by
coś zanimować. Nie wiem jak konkretnie animujesz więc tylko zgaduję.
Jeśli np. używasz innerHTML gdzieś dalej do zapisu, to wtedy takie cuda
mogą się dziać. Nie należy używać do tego celu innerHTML bo jest
strasznie wolne gdyż wymusza odświeżanie _CAŁEJ_ struktury DOM. Wtedy
okresowo możesz tracić dostęp do DOM mimo iż pozornie wydaje Ci się, że
nic się w niej nie zmienia. To dość częsty błąd początkujących
programistów JS a i zaawansowani czasem też o tym nie wiedzą.
// Animuj literkę w napisie tytułowym:

var letterIndex = -1;
var mainTitle;

function animateMainTitle() {
'use strict';
if (mainTitle === undefined) {
mainTitle = document.getElementById("main_title").innerHTML;
}
letterIndex = (letterIndex + 1) % mainTitle.length;
var s = mainTitle.substr(0, letterIndex) +
'<span class="selected_letter">' +
mainTitle.substr(letterIndex, 1) +
'</span>' +
mainTitle.substr(letterIndex + 1);
document.getElementById("main_title").innerHTML = s;
setTimeout(animateMainTitle, 100);
}

Czy gdybym zamiast innerHTML umieścił wszystkie literki w span'ach i
ustawiał tylko atrybut class odpowiedniej literki to byłoby lepiej?
Jivanmukta
2018-11-19 08:31:47 UTC
Permalink
Post by Jivanmukta
Post by Marek S
3. Ponadto z nazwy w/w funkcji wnioskuję iż naruszasz strukturę DOM by
coś zanimować. Nie wiem jak konkretnie animujesz więc tylko zgaduję.
Jeśli np. używasz innerHTML gdzieś dalej do zapisu, to wtedy takie
cuda mogą się dziać. Nie należy używać do tego celu innerHTML bo jest
strasznie wolne gdyż wymusza odświeżanie _CAŁEJ_ struktury DOM. Wtedy
okresowo możesz tracić dostęp do DOM mimo iż pozornie wydaje Ci się,
że nic się w niej nie zmienia. To dość częsty błąd początkujących
programistów JS a i zaawansowani czasem też o tym nie wiedzą.
var letterIndex = -1;
var mainTitle;
function animateMainTitle() {
    'use strict';
    if (mainTitle === undefined) {
        mainTitle = document.getElementById("main_title").innerHTML;
    }
    letterIndex = (letterIndex + 1) % mainTitle.length;
    var s = mainTitle.substr(0, letterIndex) +
            '<span class="selected_letter">' +
            mainTitle.substr(letterIndex, 1) +
            '</span>' +
            mainTitle.substr(letterIndex + 1);
    document.getElementById("main_title").innerHTML = s;
    setTimeout(animateMainTitle, 100);
}
Czy gdybym zamiast innerHTML umieścił wszystkie literki w span'ach i
ustawiał tylko atrybut class odpowiedniej literki to byłoby lepiej?
Zrobiłem tak i jest dobrze:

var letterIndex = 0;
function animateMainTitle() {
'use strict';
document.getElementById('letter' + letterIndex).className = '';
letterIndex = (letterIndex + 1) % 24;
document.getElementById('letter' + letterIndex).className =
'selected_letter';
setTimeout(animateMainTitle, 100);
}

Dzięki za pomoc.
Marek S
2018-11-19 21:57:32 UTC
Permalink
Post by Jivanmukta
    document.getElementById("main_title").innerHTML = s;
No więc widzę, że trafiłem w sedno :-) Standardowy błąd.
Post by Jivanmukta
Czy gdybym zamiast innerHTML umieścił wszystkie literki w span'ach i
ustawiał tylko atrybut class odpowiedniej literki to byłoby lepiej?
Zdecydowanie lepiej. A jeśli z jakiegoś powodu musisz zmieniać HTML, to
rób to tym:

https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML

Po to powstała ta funkcja by nie używać innerHTML.
--
Pozdrawiam,
Marek
Jivanmukta
2018-12-17 14:04:53 UTC
Permalink
Post by Marek S
Post by Jivanmukta
document.getElementById("main_title").innerHTML = s;
No więc widzę, że trafiłem w sedno :-) Standardowy błąd.
Post by Jivanmukta
Czy gdybym zamiast innerHTML umieścił wszystkie literki w span'ach i
ustawiał tylko atrybut class odpowiedniej literki to byłoby lepiej?
Zdecydowanie lepiej. A jeśli z jakiegoś powodu musisz zmieniać HTML, to
https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML
Po to powstała ta funkcja by nie używać innerHTML.
Programowania z wykorzystaniem innerHTML nauczyłem się z książek...
Dzięki za pomoc.

---
Ta wiadomość została sprawdzona na obecność wirusów przez oprogramowanie antywirusowe Avast.
https://www.avast.com/antivirus

Loading...