Sana: Abfangen von Var die leer sind, somit kein NaN als Ausgabe

Mein Ziel ist es keine NaN Ausgabe zuzulassen

Über ein Formular hole ich die Daten und überprüfe ob es eine Zahl ist.


Es funktioniert, das vorab. Aber ist es auch so richtig?



<form name="formular" action="">
<input type="text" name="input1" class="form-control" placeholder="0" onkeyup="calculate()"/>
<input type="text" name="input2" class="form-control" placeholder="0" onkeyup="calculate()"/>
<input type="text" name="input3" class="form-control" placeholder="0" onkeyup="calculate()"/>
<span  class="form-control" id="output">000</span> 
</form>	

und hier rechne ich es aus:


 function calculate() {
 	input1 = parseFloat( document.formular.input1.value.replace(/,/ , ".") );
 	input2 = parseFloat( document.formular.input2.value.replace(/,/ , ".") );
	input3 = parseFloat( document.formular.input3.value.replace(/,/ , ".") );

	if (typeof(input1)=="number" && input1+""=="NaN") { var input1 =0; }	
	if (typeof(input2)=="number" && input2+""=="NaN") { var input2 =0; }
	if (typeof(input3)=="number" && input3+""=="NaN") { var input3 =0; }
	
	document.getElementById("output").innerHTML= (input1 + input2 + input3).toString().replace(/\./ , ",");	
 }
 

Eure Sana (fromVienna)

  1. Hallo Sana,

    typeof(NaN) ist null, darum ist der erste Teil deiner Logik immer false.

    Aber du machst es Dir zu schwer. Es gibt die Funktion isNaN.

    Und du solltest das Wörtchen "var" verlegen. Wenn es bei den Plausis steht, erweckt es den Eindruck, als wolltest Du dort eine lokale Variable anlegen. Das tut var ohnehin nicht, es erzeugt Variablen im Funktionsscope.

    Es gehört also vor die Zuweisungen am Anfang. Und dann solltest Du var durch let ersetzen, das ist moderneres JavaScript und erzeugt Variablen tatsächlich so, wie man es aus C oder Java kennt: Im Scope der geschweiften Klammern, worin es steht.

    Ich habe noch ein paar Zeilenumbrüche gemacht, damit es mir nicht die Darstellung zerreißt. Und ich verwende textContent statt innerHTML für die Ausgabe, weil Du ja Text schreibst und kein HTML. Warum also den HTML Parser anwerfen?

    function calculate() {
      let input1 = parseFloat(
                      document.formular.input1.value
                              .replace(/,/ , ".") );
      let input2 = parseFloat(
                      document.formular.input2.value
                              .replace(/,/ , ".") );
      let input3 = parseFloat(
                      document.formular.input3.value
                              .replace(/,/ , ".") );
    
      if (isNaN(input1)) { input1 = 0; }	
      if (isNaN(input2)) { input2 = 0; }	
      if (isNaN(input3)) { input3 = 0; }	
    	
      document.getElementById("output").textContent =
          (input1 + input2 + input3).toString()
                                    .replace(/\./ , ",");	
    }
    

    Ja. Und dann ist mir das viel zu feucht. Ein Grundprinzip des Programmierens heißt DRY (Don't Repeat Yourself). Dieser Code schreit nach einer Funktion, die die Aufbereitung der Eingabedaten übernimmt.

    function calculate() {
      let summe = getInputAsFloat(document.formular.input1) +
                  getInputAsFloat(document.formular.input2) +
                  getInputAsFloat(document.formular.input3);
    	
      document.getElementById("output").textContent =
                     summe.toString().replace(/\./ , ",");	
    }
    
    function getInputAsFloat(element) {
      let input = parseFloat(element.value.replace(/,/ , ".") );
      return (isNaN(input)) ? 0 : input;
    }
    

    Die Zeile return (isNaN(input)) ? 0 : input; ist eine inline-Bedingung mit dem ?: Operator. Es ist die Kurzform von

      if (isNaN(input))
        return 0;
      else
        return input;
    

    Rolf

    --
    sumpsi - posui - obstruxi
    1. @@Rolf B

      function getInputAsFloat(element) {
        let input = parseFloat(element.value.replace(/,/ , ".") );
        return (isNaN(input)) ? 0 : input;
      }
      

      Wie ich an anderer Stelle schon schrieb, braucht man die die Abfrage isNaN(input) gar nicht:

      function getInputAsFloat(element) {
        const input = parseFloat(element.value.replace(/,/ , ".") ) || 0;
        return input;
      }
      

      Und da sich input nicht ändert: const, nicht let. Aber die Variable braucht man gar nicht:

      function getInputAsFloat(element) {
        return parseFloat(element.value.replace(/,/ , ".") ) || 0;
      }
      

      replace() braucht man auch nicht, wenn das Eingabefeld type="number" ist:

      function getInputAsFloat(element) {
        return element.valueAsNumber;
      }
      

      Und damit braucht man die Funktion getInputAsFloat() auch nicht.

      🖖 Stay hard! Stay hungry! Stay alive! Stay home!

      --
      Vielen Eltern dämmert beim Home-Schooling so langsam die Erkenntnis: Lehrer ist wohl doch ein regelrechter Beruf! (@heuteshow)
      1. Hallo Gunnar,

        wie ist denn jetzt die Unterstützung von <input type="number">? Ich habe mich vor etwa 2-3 Jahren damit beschäftigt, und da machte noch jeder Browser etwas anderes. Ich habe daher isNaN und replace drin gelassen.

        Gruß
        Jürgen

        1. @@JürgenB

          wie ist denn jetzt die Unterstützung von <input type="number">?

          Hm, ich hab zu HTMLInputElement.valueAsNumber weder bei Can I use noch im MDN einen Eintrag gefunden.

          Mein Addierer funktioniert aber in allen großen Browsern: Firefox, Safari, Edge, Chrome. Gibt es irgendeinen relevanten Browser, wo er nicht funktioniert?

          Für IE-Nutzer ist ja ein Fallback vorhanden: Zettel und Stift.

          🖖 Stay hard! Stay hungry! Stay alive! Stay home!

          --
          Vielen Eltern dämmert beim Home-Schooling so langsam die Erkenntnis: Lehrer ist wohl doch ein regelrechter Beruf! (@heuteshow)
          1. Hallo Gunnar,

            Für IE-Nutzer ist ja ein Fallback vorhanden: Zettel und Stift.

            Progressive Contempt halte ich für eine suboptimale Lösung.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. @@Rolf B

              Für IE-Nutzer ist ja ein Fallback vorhanden: Zettel und Stift.

              Progressive Contempt halte ich für eine suboptimale Lösung.

              Ich kann mir keinen Anwendungsfall vorstellen, wo dieser Addierer essentiell notwendig ist. Jedes OS bietet seinen Nutzern einen Taschenrechner.

              Die Einbindung des Addierers in eine Webseite erhöht den Komfort: Nutzer, bei denen das Widget läuft, müssen nicht zwischen Anwendungen wechseln. Der Addierer ist progressive enhancement.

              🖖 Stay hard! Stay hungry! Stay alive! Stay home!

              --
              Vielen Eltern dämmert beim Home-Schooling so langsam die Erkenntnis: Lehrer ist wohl doch ein regelrechter Beruf! (@heuteshow)
          2. Hallo Gunnar,

            ich habe das jetzt noch mal getestet:

            HTMLInputElement.valueAsNumber

            da liefert der IE ein NaN, aber keinen JS-Fehler.

            Der FF nimmt default einen Dezimalpunkt, akzeptiert aber auch ein Komma.

            Chrome nimmt default ein Dezimalkomma, akzeptiert aber auch einen Punkt.

            Chrome-Edge akzeptiert nur einen Punkt, das Komma ist gesperrt.

            Safari nimmt default ein Dezimalkomma, akzeptiert aber auch einen Punkt.

            toLocalString liefert im FF, Chrome und Safari ein Komma, im Chrome-Edge einen Punkt.

            Nach meinem momentanen Wissensstand ist der IE (wie üblich) dasProblem, da er valueAsNumber kennt, aber falsch ausführt.

            Meine Testseite liegt z.Zt. hier.

            Gruß
            Jürgen

            1. @@JürgenB

              Chrome-Edge akzeptiert nur einen Punkt, das Komma ist gesperrt.

              Das kann ich weder bestätigen noch nicht dementieren.

              toLocalString liefert im FF, Chrome und Safari ein Komma, im Chrome-Edge einen Punkt.

              Dito. Auf macOS verhält sich Edge 80 wie die anderen Browser auch: akteptiert Punkt und Komma bei Eingabe, gibt Komma aus (bei entsprechender Locale).

              Nach meinem momentanen Wissensstand ist der IE (wie üblich) dasProblem, da er valueAsNumber kennt, aber falsch ausführt.

              Dann sollte da noch eine feature detection, die entweder IE mit einem Polyfill versorgt oder das ganze Widget nicht anzeigt (je nach Aufwand-Nutzen-Verhältnis).

              🖖 Stay hard! Stay hungry! Stay alive! Stay home!

              PS: Könnte man was dagegen tun, dass die Screenshots so riesig angezeigr werden? Ich habe {:width="320"} angegeben, aber das wird jetzt ignoriert. Früher ging das mal. @Christian Kruse?

              --
              Vielen Eltern dämmert beim Home-Schooling so langsam die Erkenntnis: Lehrer ist wohl doch ein regelrechter Beruf! (@heuteshow)
              1. Hallo Gunnar Bittersmann,

                PS: Könnte man was dagegen tun, dass die Screenshots so riesig angezeigr werden? Ich habe {:width="320"} angegeben, aber das wird jetzt ignoriert. Früher ging das mal. @Christian Kruse?

                ?size=medium

                Bis demnächst
                Matthias

                --
                Du kannst das Projekt SELFHTML unterstützen,
                indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
                1. @@Matthias Apsel

                  PS: Könnte man was dagegen tun, dass die Screenshots so riesig angezeigr werden? Ich habe {:width="320"} angegeben, aber das wird jetzt ignoriert. Früher ging das mal. @Christian Kruse?

                  ?size=medium

                  Nein, dann werden statt der 640 × 1000 Pixel[1] großen Bilder auf 384 × 600 Pixel runtergerechnete angezeigt, die einerseits völlig verwaschen aussehen und andererseits immer noch zu groß dargestellt werden.

                  Ich will die Originalbilder in ihrer Originalgröße, also 320px × 500px[2] anzeigen lassen.

                  🖖 Stay hard! Stay hungry! Stay alive! Stay home!

                  --
                  Vielen Eltern dämmert beim Home-Schooling so langsam die Erkenntnis: Lehrer ist wohl doch ein regelrechter Beruf! (@heuteshow)

                  1. Mit Pixel sind Bildpixel gemeint. ↩︎

                  2. Mit px sind CSS-Pixel gemeint. ↩︎

          3. Lieber Gunnar,

            Für IE-Nutzer ist ja ein Fallback vorhanden: Zettel und Stift.

            das ist jetzt alles andere als inclusive oder für alle User! Der Zettel kann sich nicht mit vorher unbekannten Internetinhalten beschreiben.

            Liebe Grüße

            Felix Riesterer

            1. Hallo Felix,

              ganz meine Meinung

              Rolf

              --
              sumpsi - posui - obstruxi
  2. Guten Abend,

    	if (typeof(input1)=="number" && input1+""=="NaN") { var input1 =0; }	
    	if (typeof(input2)=="number" && input2+""=="NaN") { var input2 =0; }
    	if (typeof(input3)=="number" && input3+""=="NaN") { var input3 =0; }
    

    ich vermute mal, dass das sogar so wie gewünscht funktioniert. Aber anstatt mit den Typ- und Fehlerbezeichnern als Strings zu jonglieren, würde ich doch lieber die Abfragefunktion isNaN() verwenden.

    	document.getElementById("output").innerHTML= (input1 + input2 + input3).toString().replace(/\./ , ",");	
    

    Und warum den Dezimalpunkt wieder zu einem Komma machen?

    Live long and pros healthy,
     Martin

    --
    Ich stamme aus Ironien, einem Land am sarkastischen Ozean.
  3. Hallo,

    noch als Ergänzung zu Rolfs Antwort:

    <input type="text" name="input1" class="form-control" placeholder="0" onkeyup="calculate()"/>

    es gibt auch type="number"

    Hier würde es sich anbieten, den Eventhandler einmal am form festzumachen. Auch wäre das input-Event die bessere Wahl. Und das Event muss ja auch nicht bei jedem Tastendruck feuern,

    Ich habe da vor einiger Zeit mal etwas gebastelt.

    Gruß
    Jürgen

  4. @@Sana

    Es funktioniert, das vorab. Aber ist es auch so richtig?

    Nein.

    <form name="formular" action="">
    

    Der Wert des action-Attributs darf nicht leer sein. Du willst kein action-Attribut setzen.

    <input type="text" name="input1" class="form-control" placeholder="0" onkeyup="calculate()"/>
    

    Dem Eingabefeld fehlt seine Beschriftung (label). Auch wenn sehenden Nutzern die Funktion des Feldes klar ist, sollte das Ding dennoch eine Beschriftung haben – diese kann dann visuell versteckt sein.

    Es gibt andere Eingabeformen als Keyboard. keyup ist nicht das Event, auf das zu lauschen ist, sondern input.

    Eventhandler sollten nicht im HTML notiert werden (on…-Attribute), sondern im JavaScript (EventTarget.addEventListener()). Man braucht auch nicht einen Eventhandler für jedes Eingabefeld, sondern nur einen fürs Formular (event delegation).

    <span  class="form-control" id="output">000</span> 
    

    Zur Ausgabe gibt es ein entsprechendes HTML-Element (Ich musste das Wiki erstmal berichtigen, bevor ich das verlinken konnte. Vielleicht kann noch jemand drüberschauen, ob die Formulierung so verständlich ist.)

     	input1 = parseFloat( document.formular.input1.value.replace(/,/ , ".") );
    

    Es ist nicht nötig, das Komma in einen Punkt umzuwandeln. Für Eingabefelder vom Typ number gibt’s da HTMLInputElement.valueAsNumber.

    	if (typeof(input1)=="number" && input1+""=="NaN") { var input1 =0; }	
    

    Zum Vorbelegen von Werten kann man in JavaScript den ||-Operator nutzen.

    	document.getElementById("output").innerHTML= (input1 + input2 + input3).toString().replace(/\./ , ",");	
    

    Es ist nicht nötig, den Punkt durch Komma zu ersetzen. Das erledigt Number.toLocaleString().

    Das Ganze kannst du dir bei diesem Addierer ansehen.

    🖖 Stay hard! Stay hungry! Stay alive! Stay home!

    --
    Vielen Eltern dämmert beim Home-Schooling so langsam die Erkenntnis: Lehrer ist wohl doch ein regelrechter Beruf! (@heuteshow)
    1. @@Gunnar Bittersmann

      Das Ganze kannst du dir bei diesem Addierer ansehen.

      Ich bin mir nicht sicher, ob das mit dem Placeholder

      <input type="number"  placeholder="0"/>
      

      so eine gute Idee ist, oder ob man nicht doch besser die Eingabefelder mit dem wert 0 vorbefüllt:

      <input type="number"  value="0"/>
      

      🖖 Stay hard! Stay hungry! Stay alive! Stay home!

      --
      Vielen Eltern dämmert beim Home-Schooling so langsam die Erkenntnis: Lehrer ist wohl doch ein regelrechter Beruf! (@heuteshow)
      1. Hallo Gunnar Bittersmann,

        oder ob man nicht doch besser die Eingabefelder mit dem wert 0 vorbefüllt:

        This, imho.

        Bis demnächst
        Matthias

        --
        Du kannst das Projekt SELFHTML unterstützen,
        indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
        1. @@Matthias Apsel

          oder ob man nicht doch besser die Eingabefelder mit dem wert 0 vorbefüllt:

          This, imho.

          Naja, Placeholder hat den Charme, dass man mit der Maus ins Feld clicken und lostippen kann; die 0 verschwindet von selbst. (Genau genommen war sie nie da.)

          BTW:

          This, imho.
          {:@en}
          

          [in Simon Cowell’s voice] This doesn’t work.

          Da muss eine Leerzeile dazwischen:

          This, imho.
          
          {:@en}
          

          So wird ein <p lang="en">-Schuh draus.

          🖖 Stay hard! Stay hungry! Stay alive! Stay home!

          --
          Vielen Eltern dämmert beim Home-Schooling so langsam die Erkenntnis: Lehrer ist wohl doch ein regelrechter Beruf! (@heuteshow)