Was ist da schief (JS)?

2 Antworten

Guten Abend,

Beim ersten Ansehen ist mir folgendes aufgefallen:

if (document.querySelector("#eins", "#zwei", "#drei", "#vier", "#fünf", "#sechs", "#sieben", "#acht", "#neun").hasAttribute("class")) {...}

Probiere das mal mit document.querySelectorAll() - Diese Funktion kann mehrere Parameter (in diesem Falle Selektoren) aufnehmen und verarbeiten, was bei document.querySelector() meines Erachtens nicht der Fall ist.


The2nd 
Beitragsersteller
 17.11.2021, 21:17

Neuer Fehler:

"main.js:18 Uncaught TypeError: document.querySelectorAll(...).hasAttribute is not a function

  at clickvol2 (main.js:18)

  at HTMLParagraphElement.<anonymous> (main.js:30)"

HermCrafter  17.11.2021, 21:19
@The2nd

Der Rückgabewert von document.querySelectorAll() ist vom Typ NodeList.

Über diese Liste müsstest du nochmal mit forEach() iterieren. Möchtest du überprüfen, ob eines der Elemente die genannte Klasse hat oder alle?

The2nd 
Beitragsersteller
 17.11.2021, 21:21
@HermCrafter

Eines dieser Elemente könnte evt die Kalsse noch haben. Wenn mans so sieht ist es ne Sicherheit falls in "ClickIt" am Ende der Funktion aus welchen Gründen auch immer die Klasse "click" mit dem Design nicht removed wird.

HermCrafter  17.11.2021, 21:22
@The2nd

Also möchtest du damit erstmal überprüfen, ob eines der Elemente das Attribut class hat?

The2nd 
Beitragsersteller
 17.11.2021, 21:23
@HermCrafter

Es ist ne bestimmte Klasse aber "class" reicht da die Elemente max diese eine haben und sonst nur jeweils eine ID über die ich sie ansteuere.

HermCrafter  17.11.2021, 21:25
@The2nd

Probiere vielleicht mal das:

document.querySelectorAll(...).forEach(element => {
  if (element.hasAttribute('class')) {
    ...
  }
});

Punkte durch Argumente und Code ersetzen.

HermCrafter  17.11.2021, 21:27
@HermCrafter

Noch ein Tipp nebenbei:

Wenn du mit Klassen arbeitest, dann arbeite nicht mit dem class Attribut, sondern überprüfe mithilfe der Eigenschaft classList.

The2nd 
Beitragsersteller
 17.11.2021, 21:30
@HermCrafter

Ich glaube ich habe mich irgendwie vertippt.... Fehler ist: "Uncaught SyntaxError: Lexical declaration cannot appear in a single-statement context" und neuer Code-Schnipsel:
let clickvol2 = function() {

  if (document.querySelectorAll("#eins", "#zwei", "#drei", "#vier", "#fünf", "#sechs", "#sieben", "#acht", "#neun").forEach(element => {

    if (element.hasAttribute('class')) {

      console.log(".")

    } else {

      ClickIt(genNum())

    }

    }))

HermCrafter  17.11.2021, 21:33
@The2nd

Lass mal das if weg, die Überprüfung findet in der Schleife statt.

Und in der Schleife den Parameter bitte element und nicht e nennen.

The2nd 
Beitragsersteller
 17.11.2021, 21:36
@HermCrafter

Immerhin keine Fehler mehr aber jetzt wird die Klasse nicht mehr zugeordnet und so ist nichts gefärbt....

let genNum = function() {

    let gen = Math.random() * 9;

    let num = Math.round(gen);

    let numers = ["null", "eins", "zwei", "drei", "vier", "fünf", "sechs", "sieben", "acht", "neun"];

    let final = (numers[num]);

    if(final === "zehn") {

        genNum()

    }

    return final;

};

let i = 0;

document.getElementById("Punkteanzahl").textContent = i;

let clickvol2 = function() {

    document.querySelectorAll("#eins", "#zwei", "#drei", "#vier", "#fünf", "#sechs", "#sieben", "#acht", "#neun").forEach(element => {

        if (element.hasAttribute('class')) {

            console.log(".")

        } else {

            ClickIt(genNum())

        }

        })

let ClickIt = function(num) {

    let hash = "#";

    let ident = hash.concat(num);

    document.querySelector(ident).setAttribute("class", "click");

    document.querySelector(ident).addEventListener("click", function() {

    document.querySelector(ident).removeAttribute("class");

    clickvol2();

    i++;

})

};

ClickIt(genNum());

console.log(document.getElementById("Punkteanzahl").textContent)}

HermCrafter  17.11.2021, 21:40
@The2nd

Könntest du mir vielleicht kurz sagen, was genau der Algorithmus machen soll? Ich würde ihn dann mal umsetzen und hier posten.

The2nd 
Beitragsersteller
 17.11.2021, 21:44
@HermCrafter

Er soll 9 paragraphs rndm eine Klasse zuweisen die per css mit einem Design verbunden ist. Klickt man dieses gefärbte Feld an soll sich die Variable "i" erhöhen, die Klasse wieder removed und die Funktion erneut ausgeführt (am besten 3 Mal) werden. Hier der komplette Code:

HTML:

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Steal-botprotection</title>

    <link rel="stylesheet" href="styles.css">

</head>

<body>

    <div id="Punkte">

        <p id="Punkteanzahl"></p>

    </div>

    <div class="box">

        <p id="eins"></p>

        <p id="zwei"></p>

        <p id="drei"></p>

        <p id="vier"></p>

        <p id="fünf"></p>

        <p id="sechs"></p>

        <p id="sieben"></p>

        <p id="acht"></p>

        <p id="neun"></p>

    </div>

    <script src="main.js"></script>

</body>

</html>

JS:
"use strict";

let genNum = function() {

    let gen = Math.random() * 9;

    let num = Math.round(gen);

    let numers = ["null", "eins", "zwei", "drei", "vier", "fünf", "sechs", "sieben", "acht", "neun"];

    let final = (numers[num]);

    if(final === "zehn") {

        genNum()

    }

    return final;

};

let i = 0;

document.getElementById("Punkteanzahl").textContent = i;

let clickvol2 = function() {

    document.querySelectorAll("#eins", "#zwei", "#drei", "#vier", "#fünf", "#sechs", "#sieben", "#acht", "#neun").forEach(element => {

        if (element.hasAttribute('class')) {

            console.log(".")

        } else {

            ClickIt(genNum())

        }

        })

let ClickIt = function(num) {

    let hash = "#";

    let ident = hash.concat(num);

    document.querySelector(ident).setAttribute("class", "click");

    document.querySelector(ident).addEventListener("click", function() {

    document.querySelector(ident).removeAttribute("class");

    clickvol2();

    i++;

})

};

ClickIt(genNum());

console.log(document.getElementById("Punkteanzahl").textContent)}

CSS:
* {

    background-color: #0e163d;

}

.box {

    display: grid;

    background-color: #1e2859;

    margin: 0.5%;

    grid-template-columns: 33.33% 33.33% 33.33%;

    grid-template-rows: 30vh 30vh 30vh;

    column-gap: 0.6vh;

    row-gap: 0.6vh;

}

#Punkte {

    background-color:#ffffff;

    height: 3vh;

    margin: 1%;

}

#Punkteanzahl {

    text-align: center;

    font-family: sans-serif;

    background: #ffffff;

}

.click {

    background-color: red;

}

BeamerBen  17.11.2021, 21:45
@HermCrafter

Variablen Namen sollte man daran anpassen wie häufig sie verwendet werden. Wenn so was wie e nur für einen Block von 4 Zeilen relevant ist und die Bedeutung klar ist, wie bei .forEach, ist das ein komplett valider Variablenname. Erzähl keinen Quatsch.

HermCrafter  17.11.2021, 21:57
@BeamerBen

Ich habe das nicht gesagt, weil es kein gültiger Variablenname wäre, Ich habe es in meinem Beispiel nur deutlicher als element bezeichnet, damit das Ansinnen verständlicher wird. Dass der Compiler nicht weiß, dass e nicht element ist, brauch ich dir wohl nicht zu erklären.

BeamerBen  17.11.2021, 21:59
@HermCrafter

Dann nehm ichs zurück, geht nur aus der Historie nicht so klar hervor, denke wurde nachträglich editiert.

regex9  18.11.2021, 00:28
@The2nd

Das ist falsch:

document.querySelectorAll("#eins", "#zwei", "#drei", "#vier", "#fünf", "#sechs", "#sieben", "#acht", "#neun")

So wäre es richtig:

document.querySelectorAll("#eins, #zwei, #drei, #vier, #fünf, #sechs, #sieben, #acht, #neun")
The2nd 
Beitragsersteller
 17.11.2021, 21:16

Danek werd ich Mal ausprobieren... Hast du vielleicht sonst noch eine Idee?

Offensichtlich wird das Element nicht gefunden.

Cannot read properties of null (reading 'setAttribute')

Du versuchst .setAttribute auf einen null wert anzuwenden.

Du kannst über die Browser Tools den Code debuggen um raus zu finden bei welchem Parameter der an die Funktion übergeben wird der Fehler auftritt. Ansonsten kannst du auch mit console.log das ausgeben oder so.

Debuggen mit Firefox und Chrome:

https://developer.mozilla.org/en-US/docs/Tools/Debugger

https://developer.chrome.com/docs/devtools/javascript/

tl;dr es wird halt ein Element nicht gefunden.

PS:

    let gen = Math.random() * 9;

    let num = Math.round(gen);

    let numers = ["null", "eins", "zwei", "drei", "vier", "fünf", "sechs", "sieben", "acht", "neun"];

ist Quatsch. Definier den Array und nutze let num = Math.floor(Math.random() * numers.length)

Du willst nicht aufrunden, das Maximale Ergebnis darf höchstens 8 sein da Arrays bei 0 anfangen.

Woher ich das weiß:Berufserfahrung – Software Entwickler / Devops

The2nd 
Beitragsersteller
 17.11.2021, 21:41

Nachdem ein anderer User mir nun geholfen hat wird kein Efhler mehr engazeigt... Dafür passiert nichts mehr...

BeamerBen  17.11.2021, 21:43
@The2nd

Ich kann dir helfen wenn du deinen Code irgendwo vernünftig hochlädst, so das man ihn ausführen kann und das Problem nachvollziehen. Also inklusive HTML, auf Pastebin, git oder ähnlichem.

Ansonsten schau dir die Links aus der Antwort an, der debugger ist die beste möglichkeit solche Fehler zu lösen.

The2nd 
Beitragsersteller
 17.11.2021, 21:45
@BeamerBen

Jo kann ich machen... Einen Moment und danke für die Hilfe....

BeamerBen  17.11.2021, 22:17
@The2nd

Da passiert nichts weil du die Klammern falsch gesetzt hast. Von der einen Funktion ist die } erst ganz am Ende.

Außerdem gibts im Code das Problem was ich schon angesprochen habe, nämlich das du aufrundest.

Ein weiteres Problem ist die "#null" im Array. #null gibts im HTML nicht.

Dann scheinst du den EventListener nicht richtig zu removen das scheint auch Probleme zu machen und mehrere Felder werden rot, das willst du ja denke ich nicht. würde vermutlich einfach schauen das ich einen Event Listener auf das Div mache oder so in dem alles drinnen ist denke ich.

Der Counter an sich geht, außer das er mehrmals erhöht wird wegen dem Event Listener Problem, du schreibst ihn nur nicht ins dom wenn er aktualisiert wird.

The2nd 
Beitragsersteller
 17.11.2021, 22:20
@BeamerBen

? Dann ist es ja net mehr das was erreicht werden soll... Es soll nur etwas passieren wenn das ausgewählte Feld getippt wird...

The2nd 
Beitragsersteller
 17.11.2021, 22:25
@BeamerBen

Und was heißt Counter ins DOM schreiben (Ich weiß schon was DOM ist aber nicht in dem Zusammenhang)? Wie geht das?

BeamerBen  17.11.2021, 22:26
@The2nd
document.getElementById("Punkteanzahl").textContent = i;

scheinst du nur am Anfang ein mal zu machen, aber nicht wenn der Counter aktualisiert wird. Zumindest wenn ich deinen Code richtig interpretiere.

Ich kann eventuell dir ne korrigierte Version geben.

The2nd 
Beitragsersteller
 17.11.2021, 22:30
@BeamerBen

Ja da wäre ich dir sehr verbunden... Vielleicht kannst du es dann auch anhand dieser erklären? Möchte ja auch was mitnehmen....

The2nd 
Beitragsersteller
 17.11.2021, 22:31
@BeamerBen

Das mit der DOM hat aufjedenfall funktioniert... KAnn ich jetzt für das nächste Mal direkt besser anwenden.

BeamerBen  17.11.2021, 22:46
@The2nd

https://pastebin.com/tbTWQWE8

Also außer den angesprochenen Sachen wie Math.floor statt round und eben die null aus dem Array entfernt, hab ich die Functions umbennant und ein removeEventListener hinzugefügt. Die anonyme function für den listener ebenfalls entfernt und da einfach das übergeben was vorher clickvol2 oder so war.

Dafür nimmt dieser listener jetzt auch das clickEvent als Parameter an und statt auf die ID zu gehen passiert das removeAttribute einfach über das event target.

Hab außerdem den Code einfach mal automatisch formatieren lassen, macht es direkt leserlicher. Alles in eine Datei gepackt weils für Pastebin besser funktioniert.