Linuchs: Javascript: input-Element nachträglich einbinden - oninput und onblur funzen nicht

Moin,

für unseren Chorverband mache ich eine Webseite, in der Chöre ihre Setliste (Lieder beim Auftritt) eingeben können, als PDF speichern und der GEMA senden.

Der Gag: Mehr als 1000 Titel in der DB, die beim Tippen vorgeschlagen werden mit Komponist usw.

Etwa 15 Titel passen auf eine Seite. Wenn die nicht ausreichen, können leere Positionen ergänzt werden.

Die baue ich per Javascript ein.


  // 3. input-Element definieren
  let input_1         = document.createElement("input");
  if ( i==1 )
    input_1.required  = "required";
  input_1.id          = "titel_" +i;
  input_1.type        = "text";
  input_1.classList   = "rest bold";
  input_1.name        = "titel[" +i +"]";
  input_1.title       = 'titel_required varchar(50)';
  input_1.size        = 70;
  input_1.style       = "position:relative;max-width:100%";
  input_1.maxlength   = 70;
  input_1._alue       = '[titel]';
  input_1.placeholder = "Titel " +i;
  input_1.autocomplete= "off";
  input_1.oninput     = "getLieder( this )";
  input_1.onblur      = "getLiederSchliessen()";

Klappt soweit bis auf oninput und onblur, die sind im Code nicht zu sehen, also keine Verbindung zur DB.

Wie handelt man diese beiden „Eigenschaften“?

Gruß, Linuchs

  1. Moin Linuchs,

    Die baue ich per Javascript ein.

    
      // 3. input-Element definieren
      let input_1         = document.createElement("input");
      if ( i==1 )
        input_1.required  = "required";
      input_1.id          = "titel_" +i;
      input_1.type        = "text";
      input_1.classList   = "rest bold";
      input_1.name        = "titel[" +i +"]";
      input_1.title       = 'titel_required varchar(50)';
      input_1.size        = 70;
      input_1.style       = "position:relative;max-width:100%";
      input_1.maxlength   = 70;
      input_1._alue       = '[titel]';
      input_1.placeholder = "Titel " +i;
      input_1.autocomplete= "off";
      input_1.oninput     = "getLieder( this )";
      input_1.onblur      = "getLiederSchliessen()";
    

    Klappt soweit bis auf oninput und onblur, die sind im Code nicht zu sehen, also keine Verbindung zur DB.

    Wie handelt man diese beiden „Eigenschaften“?

    Davon ausgehend, dass es „globale Funktionen” (auf window) sind (was dir vermutlich von anderen Kritik einbringen wird, aber sei's drum), kannst du eine Eigenschaft von Funktionen nutzen:

    Function.prototype.toString() liefert dir einen String mit der Implementierung zurück. (Ausnahme sind dabei vom Browser bereitgestellte Funktionen. Da siehst du den Funktionskörper nicht).

    Schau hier, dass auch die richtigen Werte in der Funktion ankommen. Unter Umständen hilft hierbei auch ein gut gesetztes bind().

    Gruß,

    --
    a.k.a. André
  2. Hallo,

    du solltest zunächst verstehen, was die Unterschiede zwischen Methoden, Attributen und EVents für ein HTML-Element sind und wie man diese definiert.

    input und blur sind Events und entsprechend musst du diese definieren via EventListener, was beim event gemacht werden soll. Also so:

    const blurFunction = function(event){
       console.log("blur event was triggered")
    };
    
    // eventFunction definieren
    input_1.addEventListener("blur", blurFunction);  
    

    Und als Zusatzinfo, du solltest einen Debouncer einbauen. D.h. wenn Text eingegeben wird, sollte nicht sofort die Anfrage an die Datanbank gehen, sondern zeitverzögert, wenn nicht mehr getippt wird. Ansonsten ist es schlecht für die Performance. Debouncing Lösungen gibt es viele. Hier ein paar Lösungsansätze: Debouncing für Suchanfragen

    Gruss

  3. Hallo Linuchs,

    Gunnar hat Dir bestimmt schon sieben Mal gesagt, dass Placeholder kein Ersatz für Labels sind. Ich sage es Dir hiermit zum achten Mal.

    Klappt soweit bis auf oninput und onblur, die sind im Code nicht zu sehen, also keine Verbindung zur DB.

    Könntest Du dieses Problem vielleicht mit mehr und klareren Worten beschreiben? Für mich ist dieser Satz unverständliches Kauderwelsch. Wieso ist es für die Verbindung zur DB relevant, ob die oninput und onblur-Eigenschaften im Code zu sehen sind? Wobei ich auch nicht verstehe, warum sie nicht zu sehen sein sollten.

    Jedes input-Element hat die oninput und onblur-Eigenschaft. Darin findest Du die Funktion, die der Browser Dir aus dem String generiert hat, den Du im oninput- bzw. onblur-Attribut notiert hast. Willst Du den Attributinhalt, dann verwende bspw. den Methodenaufruf inputElem.getAttribute("oninput"). Aber ich wüsste nicht, wofür das von Bedeutung wäre.

    Das input-Element selbst übergibst Du ja eh als Parameter an getLieder, und das ist das eigentlich wichtige im Eventhandling. Ich hoffe, du legst um die input-Elemente einer Titelgruppe zumindest ein div. Damit fällt die Navigation zu den Nachbarinputs deutlich leichter.

    Dass es sinnvoller ist, Eventhandling mit addEventListener zu betreiben, und dass ein Debouncer für die Suche sinnoll ist, kann ich nur unterschreiben. Zu beiden Themen findest Du einiges im Selfwiki.

    Grundsätzlich würde ich die Eventlistener aber auch nicht auf den inputs direkt definieren, sondern auf einem gemeinsamen Elternelement und dann das Bubbling nutzen. Mal angenommen, das HTML sähe so aus (du hast doch eine Liste für die Titelliste verwendet, oder?)

    <ol class="titelListe">
    <li>
      <div>
        <label for="titel_1">Titel</titel>
        <input type="text" id="titel_1" name="titel_1" required ...>
      </div>
      <div>
        <label for="komponist_1">Komponist</titel>
        <input type="text" id="komponist_1" name="komponist_1" ...>
      </div>
      <div>
        <label>Bearbeiter</titel>
        <input type="text" id="bearbeiter_1" name="bearbeiter_1" ...>
      </div>
    </li>
    ...
    </ol>
    

    Praktisch wird es anders aussehen, wegen der vergrößerten Indexnummern. Stylen kannst Du das jedenfalls alles ausgehend von .titelListe.

    Die Eventhandler für input und blur definiere dann auf dem ol Element!!!

    const titelListe = document.querySelector(".titelListe");
    titelListe.addEventListener("input", getLieder);
    titelListe.addEventListener("blur", getLiederSchliessen);
    
    function getLieder(inputEvent) {
       const eingabe = inputEvent.target;      // Das input-Element, das das Event gefeuert hat
       const eintrag = eingabe.closest("li");  // Das li-Element dieser Eingabegruppe
    
       const titel = eintrag.querySelector("input[name^=titel]");
       const kompo = eintrag.querySelector("input[name^=kompo]");
       const bearb = eintrag.querySelector("input[name^=bearb]");
    
       // Jetzt hast Du alle 3 Felder im Zugriff
       if (eingabe == titel) {   // Es wurde etwas im Titel eingegeben
        ... suchen
        titel.value=suchErgebnis.titel;
        kompo.value=suchErgebnis.komponist;
        bearb.value=suchErgebnis.bearbeiter;
       }
    }
    function getLiederSchließen(blurEvent) {
    }
    

    Ich kann den richtigen Code jetzt natürlich nur andeuten, bei Dir ist das in Callbacks vom Ajax-Aufruf verpackt. Aber ich hoffe, ich konnte Dir die Idee zeigen.

    Für einen neuen Eintrag baust Du Dir das innerHTML für das neue li Element als String zusammen. Und zwar in einer Funktion, damit Du prima mit einem Template-String arbeiten kannst, um die Indexnummer überall einzusetzen wo sie gebraucht wird. Welche das ist, musst Du natürlich erstmal rausfinden - aber das hast Du ja eh schon drin.

    titelListe.append(createNewItem(index));
    
    
    function createNewItem(index) {
       item = document.createElement("li");
       item.innerHTML = 
    `<div>
        <label for="titel_${index}">Titel</titel>
        <input type="text" id="titel_${index}" name="titel_${index}" required ...>
      </div>
      <div>
        <label for="komponist_${index}">Komponist</titel>
        <input type="text" id="komponist_${index}" name="komponist_${index}" ...>
      </div>
      <div>
        <label for="bearbeiter_${index}">Bearbeiter</titel>
        <input type="text" id="bearbeiter_${index}" name="bearbeiter_${index}" ...>
      </div>`;
    
       return item;
    }
    

    Im Detail wird das bei Dir natürlich anders aussehen.

    Rolf

    --
    sumpsi - posui - obstruxi
  4. Lieber Linuchs,

      input_1.autocomplete= "off";
      input_1.oninput     = "getLieder( this )";
      input_1.onblur      = "getLiederSchliessen()";
    

    Du verwendest uralte JavaScript-Mechanismen, von denen Du besser die Finger lassen solltest, weil sie damals mangels besserer Alternativen eine Notlösung waren.

    Du notierst mit input_1.onirgendwas = "ein String" im Grunde den Textinhalt eines HTML-Attributs gleichen Namens (hier onirgendwas). Was Du hier stattdessen tun solltest, ist einen passenden EventListener zu notieren:

    input_1.addEventListener("irgendwas", function (event) {
      // hier passiert etwas wenn das Event "irgendwas" feuert
    });
    
    // das gleiche mit einer Pfeilfunktion für input-Events
    input_1.addEventListener("input", event => {
      // event ist vom Typ "input"
    });
    
    // wenn Du eine Funktion öfters benötigst
    function meineBlurFunktion (node) {
      // node ist eine Referenz auf ein <input> element
    }
    
    // die anonyme Funktion (zweiter Parameter nach "blur")
    // enthält eine gekapselte Variable "input_1" (Closure):
    input_1.addEventListener("blur", function () {
      meineBlurFunktion(input_1);
    });
    

    Bitte lasse künftig ab von diesen veralteten onirgendwas-Attributen/-Eigenschaften! Du machst Dir das Leben damit nicht leichter, weil Du nicht sicher sagen kannst, warum etwas (nicht) funktioniert.

    unser Wiki zu Eventhandler-Funktionen und wie man sie an Elemente bindet

    Liebe Grüße

    Felix Riesterer

    1. @@Felix Riesterer

      Du notierst mit input_1.onirgendwas = "ein String" im Grunde den Textinhalt eines HTML-Attributs gleichen Namens (hier onirgendwas). Was Du hier stattdessen tun solltest, ist einen passenden EventListener zu notieren:

      Das gehört in jedes Stylesheet: 😏

      [onclick], [onfocus], [onblur], [oninput], [onchange], [onsubmit], [onerror] {
        outline: medium solid orange !important;
        --WARNING: 'use `addEventListener()` instead of `on*` attribute';
      }
      

      (Möglicherweise habe ich noch das ein oder andere [on…] vergessen.)

      🖖 Live long and prosper

      --
      “In my home, the America I love, the America I've written about, that has been a beacon of hope and liberty for 250 years, is currently in the hands of a corrupt, incompetent and treasonous administration. Tonight, we ask all who believe in democracy and the best of our American spirit, to rise with us, raise your voices against authoritarianism, and let freedom reign.”
      — Bruce Springsteen, Manchester 2025-05-14
      1. Dieser Beitrag wurde gelöscht: Der Beitrag ist ein Duplikat eines anderen Beitrags.
      2. @@Gunnar Bittersmann

        Das gehört in jedes Stylesheet: 😏

        [onclick], [onfocus], [onblur], [oninput], [onchange], [onsubmit], [onerror] {
          outline: medium solid orange !important;
          --WARNING: 'use `addEventListener()` instead of `on*` attribute';
        }
        

        (Möglicherweise habe ich noch das ein oder andere [on…] vergessen.)

        Möglicherweise. Eben aber noch in @Linuchs’ Code gesehen, dass ich noch was anderes vegessen habe:

        [placeholder] {
          outline: medium solid orange !important;
          --WARNING: 'don’t use placeholder';
        }
        

        🖖 Live long and prosper

        --
        “In my home, the America I love, the America I've written about, that has been a beacon of hope and liberty for 250 years, is currently in the hands of a corrupt, incompetent and treasonous administration. Tonight, we ask all who believe in democracy and the best of our American spirit, to rise with us, raise your voices against authoritarianism, and let freedom reign.”
        — Bruce Springsteen, Manchester 2025-05-14
      3. Lieber Gunnar,

        (Möglicherweise habe ich noch das ein oder andere [on…] vergessen.)

        gibt es dafür keine Wildcard-Schreibweisen wie es ja schon bei den Attributwerten [class^="on"] möglich ist?

        Liebe Grüße

        Felix Riesterer

        1. @@Felix Riesterer

          (Möglicherweise habe ich noch das ein oder andere [on…] vergessen.)

          gibt es dafür keine Wildcard-Schreibweisen wie es ja schon bei den Attributwerten [class^="on"] möglich ist?

          War auch mein erster Gedanke. Der zweite dann: Moment mal, gibt’s das überhaupt? AFAIK gibt’s das nur für Attributwerte, nicht für Attributbezeichner.

          🖖 Live long and prosper

          --
          “In my home, the America I love, the America I've written about, that has been a beacon of hope and liberty for 250 years, is currently in the hands of a corrupt, incompetent and treasonous administration. Tonight, we ask all who believe in democracy and the best of our American spirit, to rise with us, raise your voices against authoritarianism, and let freedom reign.”
          — Bruce Springsteen, Manchester 2025-05-14
          1. Lieber Gunnar,

            AFAIK gibt’s das nur für Attributwerte, nicht für Attributbezeichner.

            eine ganz klare Lücke im Konzept! Wer ist schuld? Wen muss man da anpampen? Wann wird das endlich besser? Wenn ich doch nur Geduld hätte...

            Liebe Grüße

            Felix Riesterer

            1. Moin Felix,

              AFAIK gibt’s das nur für Attributwerte, nicht für Attributbezeichner.

              eine ganz klare Lücke im Konzept! Wer ist schuld? Wen muss man da anpampen?

              TC39.

              Gruß,

              --
              a.k.a. André
              1. @@Ryuno-Ki

                AFAIK gibt’s das nur für Attributwerte, nicht für Attributbezeichner.

                eine ganz klare Lücke im Konzept! Wer ist schuld? Wen muss man da anpampen?

                TC39.

                Und was genau hat ECMAScript mit einem CSS-Feature zu tun?

                🖖 Live long and prosper

                --
                “In my home, the America I love, the America I've written about, that has been a beacon of hope and liberty for 250 years, is currently in the hands of a corrupt, incompetent and treasonous administration. Tonight, we ask all who believe in democracy and the best of our American spirit, to rise with us, raise your voices against authoritarianism, and let freedom reign.”
                — Bruce Springsteen, Manchester 2025-05-14
                1. Moin Gunnar,

                  @@Ryuno-Ki

                  AFAIK gibt’s das nur für Attributwerte, nicht für Attributbezeichner.

                  eine ganz klare Lücke im Konzept! Wer ist schuld? Wen muss man da anpampen?

                  TC39.

                  Und was genau hat ECMAScript mit einem CSS-Feature zu tun?

                  Nicht mein Tag heute.

                  CSS WG gibt es auch auf GitHub.

                  Gruß,

                  --
                  a.k.a. André
                  1. @@Ryuno-Ki

                    Nicht mein Tag heute.

                    Das dachte ich mir schon. Damit bist du genug gestraft. Ich habe davon abgesehen, dich noch zusätzlich mit einem Minus zu strafen. 😉

                    CSS WG gibt es auch auf GitHub.

                    Ja, aber ich denke, @Felix Riesterer kann die Aussichten auf Realisierung realistisch einschätzen. HTML-Attribute sind nicht so benannt, als dass sie sich mit Stringanfang oder -ende sinnvoll gruppieren ließen. Die on…-Dinger wären da die Ausnahme.

                    In erster Linie aber ließ Felix’ Posting schon durch die Wahl der Sprache erkennen, dass es nicht so ganz ernst gemeint war.

                    Ich verfasse solche Postings auch desöfteren – ohne sie durch Smileys zu kennzeichnen (und damit den Charme etwas zunichtezumachen); jüngstes Beispiel. Ich baue da auf die Urteilskraft der Leser, aber es findet sich immer mal jemand, der keinen Spaß versteht.

                    🖖 Live long and prosper

                    --
                    “In my home, the America I love, the America I've written about, that has been a beacon of hope and liberty for 250 years, is currently in the hands of a corrupt, incompetent and treasonous administration. Tonight, we ask all who believe in democracy and the best of our American spirit, to rise with us, raise your voices against authoritarianism, and let freedom reign.”
                    — Bruce Springsteen, Manchester 2025-05-14
                    1. Moin Gunnar,

                      Ich baue da auf die Urteilskraft der Leser, aber es findet sich immer mal jemand, der keinen Spaß versteht.

                      Jein. Neurodiversität ist ein weites Feld.

                      Damit auch ein anderes Thema, was hier nicht reinpasst.

                      Gruß,

                      --
                      a.k.a. André
    2. Hallo Felix Riesterer,

      // die anonyme Funktion (zweiter Parameter nach "blur")
      // enthält eine gekapselte Variable "input_1" (Closure):
      input_1.addEventListener("blur", function () {
        meineBlurFunktion(input_1);
      });
      

      Besser nicht. Jedenfalls nur unter der Voraussetzung, dass input_1 als const deklariert ist.

      Closures sind besser als globale Variablen, aber man sollte trotzdem nach Möglichkeit vermeiden, aus einer Funktion heraus auf Daten des Elternkontexts zuzugreifen. Ich würde die target-Eigenschaft des event-Objekts zu bevorzugen. Entweder gleich bei Übergabe an meineBlurFunktion, oder man schreibt explizit einen blur-Handler und vermeidet damit die Mediator-Funktion. Ein blur-Handler lässt sich auch wieder deregistrieren (was Linuchs ebenfalls nicht zu benötigen scheint).

      // So
      input_1.addEventListener("blur", function (blurEvent) {
        meineBlurFunktion(blurEvent.target);
      });
      
      // Oder so
      input_1.addEventListener("blur", handleBlurOnInput);
      
      function handleBlurOnInput(blurEvent) {
         ...
      }
      

      Wobei Linuchs – sofern ich das richtig verstand – der Blur-Funktion gar keine Daten mitgibt, sondern lediglich das Auswahlfenster schließt.

      Und wenn ich nochmal darauf hinweisen darf: gerade wenn man Forms dynamisch erweitert, ist es in den meisten Fällen hilfreich, die Eventhandler ein einzigs Mal auf dem Form zu registrieren und die Events dahin blubbern zu lassen, statt on the fly einen Eventhandler nach dem anderen ins DOM zu kleben.

      Rolf

      --
      sumpsi - posui - obstruxi