apfelsine: Select Li Element on Keyup

Hallo,

ich möchte aus einer Liste, die nach einer Texteingabe unter der Textbox angezeigt werden mit dem Key-Up und Key-Down Werte auswählen. Dabei gibts 1 bis 2 Probleme

Ich habe dazu eine Klasse ".Selected" erstellt, wo ich den Hintergrund-Farbwert festlege. Als Test, habe ich einem Punkt in der Liste die Klasse zugeordnet. Leider wird die Farbveränderung aber nicht angezeigt.

<div id="targetDiv">
  <input id="StartStation" autocomplete="off" class="valid" type="text">
  <input id="SelectedStationStart" name="SelectedStationStart" type="hidden">
  <ul id="targetUI">
  <li id="359" onclick="javascript:setAutoComplete(359, 'Achim','StartStation','SelectedStationStart')">Achim</li>

  **<li id="419" class=".selected" onclick="javascript:setAutoComplete(419, 'Achmer','StartStation','SelectedStationStart')">Achmer</li>** 
…
  1. Key-down markiert Wert. Was dann hoffentlich funktioniert wenn 1) funkt

JSFiddle Beispiel

Sicher hab ich irgendwo einen Fehler reingebastelt...

wäre schön wenn mir jemand was sagen könnte.

lg apfelsine

akzeptierte Antworten

  1. Warum muss ich zur Korrektur eines Links jetzt extra nochmal einen Beitrag schreiben … eine Restriktion die mich hinreichend nervt.

    Es fehlte im JSFiddle die Jquery Bibliothek, hab sie angefügt:

    https://jsfiddle.net/nz42k12s/17/?utm_source=website&utm_medium=embed&utm_campaign=nz42k12s

    1. Hallo,

      Warum muss ich zur Korrektur eines Links jetzt extra nochmal einen Beitrag schreiben

      weil das Zeitfenster für Korrekturen schon geschlossen war.

      … eine Restriktion die mich hinreichend nervt.

      beliebig lange Korrigieren zu dürfen kann aber noch mehr nerven.

      Gruß
      Jürgen

      1. Hallo JürgenB,

        weiß nicht - solange keiner geantwortet hat sollte man seine eigenen Fragen schon bearbeiten dürfen; das Zeitfenster finde ich auch merkwürdig.

        Rolf

        --
        Dosen sind silbern
        1. Hallo Rolf,

          weiß nicht - solange keiner geantwortet hat sollte man seine eigenen Fragen schon bearbeiten dürfen; das Zeitfenster finde ich auch merkwürdig.

          nicht geantwortet oder nicht gelesen?

          Über die maximale Dauer der Bearbeitungsmöglichkeit kann man mMn diskutieren, aber eine Maximalzeit sollte es schon geben.

          Gruß
          Jürgen

          1. Es gibt IMHO dafür bessere Lösungen. Wenn es nur darum geht, zu erkennen, das es geändert worden ist, zum Beispiel eine optische Markierung das der Beitrag bearbeitet wurde.

            1. Hallo

              Wenn es nur darum geht, zu erkennen, das es geändert worden ist, zum Beispiel eine optische Markierung das der Beitrag bearbeitet wurde.

              Die gibt es bereits. Einem Leser zuzumuten, die Versionen eines Postings abzugleichen, um relevante Änderungen an einem Posting nachzuvollziehen, die Auswirkungen auf eine oder mehrere Antworten haben, ist noch unzumutbarer.

              Tschö, Auge

              --
              Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
              Toller Dampf voraus von Terry Pratchett
              1. Einem anderen Leser der hinterher kommt, eine Lösung für etwas sucht und dann erst in einem Baum irgendwo einen Hinweis finden muss, das es dazu noch eine andere Änderung gab auch. Wir kommen da einfach nicht auf einen Nenner ... es ist ok. Ich werde es überleben.

    2. Hallo

      Warum muss ich zur Korrektur eines Links jetzt extra nochmal einen Beitrag schreiben … eine Restriktion die mich hinreichend nervt.

      Weil es hier, wie wohl in sehr vielen Systemen (unter Anderem [1]) ein Zeitlimit für Änderungen am Posting gibt. Ob man dieses Limit anheben oder gar abschaffen sollte, wurde mehrfach diskutiert und bisher abschlägig beschieden.

      Tschö, Auge

      --
      Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
      Toller Dampf voraus von Terry Pratchett

      1. Zudem kannst du dein Posting nicht mehr bearbeiten, wenn jemand vor dem Ablauf der 15-Minuten-Frist darauf geantwortet hat. ↩︎

      1. Weil es hier, wie wohl in sehr vielen Systemen

        Eine neue Mode, die mir einfach nur auf den Zeiger geht. Das es andere kopieren macht es nicht besser.

        1. Hallo

          Weil es hier, wie wohl in sehr vielen Systemen

          Eine neue Mode, die mir einfach nur auf den Zeiger geht.

          Welche neue Mode? Solche Beschränkungen, insbesondere die beschriebene zeitliche Beschränkung, wird in vielen Foren-und Boardsystemen seit Langem eingesetzt. Zugegeben, in früheren Versionen des auf selfhtml.org eingesetzten CForums gab es keine solchen Beschränkungen. Da konnte man sein Posting einfach überhaupt nicht editieren. Nicht existente Features brauchen halt auch keine Beschränkungen.

          Das es andere kopieren macht es nicht besser.

          Wer hier von wem kopiert, sei mal dahingestellt.

          Tschö, Auge

          --
          Wenn man ausreichende Vorsichtsmaßnahmen trifft, muss man keine Vorsichtsmaßnahmen mehr treffen.
          Toller Dampf voraus von Terry Pratchett
      2. Hallo Auge,

        Zudem kannst du dein Posting nicht mehr bearbeiten, wenn jemand vor dem Ablauf der 15-Minuten-Frist darauf geantwortet hat.

        Es müssten sogar 20 Minuten sein.

        Gruß
        Julius

  2. Hallo apfelsine,

    1. nimm den Punkt aus class=".selected" weg
    2. aktiviere jQuery im Fiddle…

    Rolf

    --
    Dosen sind silbern
    1. Aaaah DANKE du bist ein Schatz 😂 Ich verrate jetzt nicht wie lange ich da schon reingestarrt habe...

  3. @@apfelsine

      <li id="359" onclick="javascript:setAutoComplete(359, 'Achim','StartStation','SelectedStationStart')">Achim</li>
    

    Was alle Antwortenden bislang übersehen haben (obwohl sie es besser wissen sollten): Das kann nicht funktionieren (im Sinne von: bei allen Nutzern funktionieren). li ist kein interaktives Element; das ist bei Tastatursteuerung nicht erreichbar, also nicht anclickbar.

    Merke: Niemals nicht-interaktive Elemente als Target für click-Events vorsehen. Für sowas sind buttons zu verwenden.

    Aber eigentlich willst du gar kein JavaScript, sondern eine Combobox? So mit list-Attribut und datalist-Element?

    Oder doch etwas JavaScript: Lea Verous Awesomplete?

    Oder willst du ausschließlich deine vorgegebenen Werte als Eingabemöglichkeiten zulassen? Dann willst du select mit options oder eine Gruppe von Radio-Buttons (vorzugsweise letzteres).

    LLAP 🖖

    --
    “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
    1. Hallo Gunnar,

      danke für deine Anregung! Ich werde es ausprobieren.

      kurze Antwort: ja, ich will eine Combobox plus. Eine die eine Id zurückliefert und nicht den ausgewählten Text.

      Ich hätte gerne - ohne jQuery-: Ein Textfeld, wo man Ortsnamen eingeben kann. Alsdann erscheint eine Dropdownliste aus der man seinen Ortsnamen auswählen kann. Ab einer gewissen Zahl an Buchstaben sende ich eine Anfrage an den Server, der mir eine gefilterte Liste liefert. Die Elemente dieser Liste sollen unter der Textbox dargestellt werden. Das ganze soll gekapselt werden, sodass ich mit relativ wenig Code aus einem normalen Textfeld ein weiteres Dropdownfeld machen kann. Möglicherweise gibt es noch Anforderungen das einzelne Buchstaben fett geschrieben werden und was weiß ich. Ich möchte volle Kontrolle über die Darstellungsweise. Die Id des gewählten Ortsnamen wird in ein verstecktes Feld geschrieben, das später zusammen mit einem Formular für eine andere Anfrage versendet wird.

      Im Grunde genommen ist es mir egal, ob es **li ** ist oder ein anderes Element. Ich habe verschiedene Wissenslücken. Deshalb ist mein Anliegen, Stück für Stück vorzugehen. Daher hab ich erstmal mein angestaubtes Wissen verwendet, aus vor der Zeit von jQuery, was mir geläufig ist und wo ich wusste, es funktioniert erstmal irgendwie. Ja, ich bin nicht mehr sehr fit in Javascript und Html. Mein Wissen ist definitiv veraltet und jQuery bereitet mir mit seinen verschachtelten Funktionen mehr Kopfschmerzen als ich Lust habe. jQuery will ich nicht wirklich verwenden, ausser für die kleineren Dinge. Beim letzten Update meines Projektes auf die neue Version von NopCommerce waren einige dieser netten Funktionen nicht mehr lauffähig, warum auch immer. Es ist - aus meiner Perspektive - ausserdem schwer zu lesen und zu durchschauen.

      Es ist nicht ganz leicht auf Anhieb zu erkennen, wo ich was ändern muss, damit die Box am Ende so aussieht und sich verhält, wie ich das will, sodass sie sich in den Rest der Seite integriert.

      Es ist ein gigantisches Projekt und ich stehe ziemlich alleine da. Von daher bin ich einfach nur froh, wenn diese Box im ersten Schritt erstmal tut was sie soll, und das tut sie auch. Auch wenn ich das Rad dafür eben selber nochmal erfinden muss. Denn eigentlich ist das ja "nur" 1 Werkzeug für viel mehr. Trotzdem habe ich mir die Zeit genommen, weil ich hoffe es besser zu kapseln als es bisher gelöst ist, sodass es eben auch besser zu warten ist. Formschön kann und will ich es jetzt Stück für Stück machen. Deshalb danke für deinen Input! :-)

      Es wird auch nicht die einzige Box bleiben die so arbeiten soll, deshalb ist mein Ziel es in eine Klasse auszulagern. Zumindest hab ich gelesen das es das jetzt geben soll. Allerdings funktioniert das nicht so recht.

      Ich finde diesen Mix aus HTML, Javascript und C# in einem einzigen Dokument ein bisschen schrecklich. Noch nie war es so leicht, verwirrenden Spagetthicode zu produzieren.

      1. @@apfelsine

        Ich hätte gerne - ohne jQuery-: Ein Textfeld, wo man Ortsnamen eingeben kann. Alsdann erscheint eine Dropdownliste aus der man seinen Ortsnamen auswählen kann. Ab einer gewissen Zahl an Buchstaben sende ich eine Anfrage an den Server, der mir eine gefilterte Liste liefert.

        Das kann mehrere Sekunden dauern und dürfte für eine Interaktion viel zu langsam sein.

        Du müsstest wohl deine Liste mit Ortsnamen zum Client schicken und die Filterund dort vornehmen lassen – mit JavaScript.

        LLAP 🖖

        --
        “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
        1. Wenn es weniger Einträge wären, ja. So habe ich es vorher gehabt. Für mehrere tausend, warte ich lieber 3 Buchstaben ab und habe dafür eine wesentlich kleinere Liste, die ich dann on the fly weiter filtern kann.

          1. @@apfelsine

            … warte ich lieber 3 Buchstaben ab und habe dafür eine wesentlich kleinere Liste, die ich dann on the fly weiter filtern kann.

            Ich sehe den Sinn darin nicht. Ein Nutzer wird kaum nach 3 eingetippten Buchstaben anhalten und warten, ob sich da eine Liste öffnet. (Falls er es überhaupt weiß, dass sich da was tut.) In der Zeit, bis die Liste kommt, hat er den Ortsnamen längst zuende getippt.

            LLAP 🖖

            --
            “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
    2. @@apfelsine

        <li id="359" onclick="javascript:setAutoComplete(359, 'Achim','StartStation','SelectedStationStart')">Achim</li>
      

      Was alle Antwortenden bislang übersehen haben (obwohl sie es besser wissen sollten): Das kann nicht funktionieren (im Sinne von: bei allen Nutzern funktionieren). li ist kein interaktives Element; das ist bei Tastatursteuerung nicht erreichbar, also nicht anclickbar.

      Merke: Niemals nicht-interaktive Elemente als Target für click-Events vorsehen. Für sowas sind buttons zu verwenden.

      ok. Nun habe ich mal nachgeschaut was es denn sonst noch so gibt außer Buttons.
      https://wiki.selfhtml.org/wiki/HTML/Kategorien_von_Elementen#Interaktive_Elemente

      Irgendwo habe ich gelesen A wäre nicht gut für onclick. Aber mal so einfach gefragt, kann man nicht auch ein Label verwenden? Meinetwegen nehme ich auch einen Button. Ich will es einfach nur wissen.

      Ich habe es jetzt mal so probiert(siehe unten), aber das Event anhängen funktioniert nicht, weil das dynamische Element, das ich dem DIV "targetUI" hinzufüge nicht gefunden wird und dadurch das Objekt "myelement" leer ist:

      var div = document.getElementById('targetUI');
      newelement = '<li  class="selected"> <label name="' + item[0] + '" id="' + item[0] + '">' + item[1] + '</label></li>';
      
      if (div != null) {
      div.innerHTML += newelement;
                                                  
      var elementname = '\"' + item[0] + '\"';
      var myelement= div.getElementsByTagName(elementname);
      if (myelement!= null) {
          AddEvent(myelement, 'click', function () { 
              setAutoComplete(item[0], '\'' + item[1] + '\'', '\'' + parent + '\'', '\'' + idField + '\'') });
           }
       }
      
      1. Hey

        Für sowas sind buttons zu verwenden.

        Nun habe ich mal nachgeschaut was es denn sonst noch so gibt außer Buttons.

        Einiges. Aber für sowas sind buttons zu verwenden.

        Irgendwo habe ich gelesen A wäre nicht gut für onclick.

        Ein a Element verwendet man um einen Link zu setzen. Das funktioniert ohne Zutun eines Skripts. Wenn du keinen Link setzen möchtest, ist a nicht das richtige Element.

        Aber mal so einfach gefragt, kann man nicht auch ein Label verwenden?

        Ein label wird verwendet um ein anderes Element zu beschriften. Ein label das kein anderes Element beschriftet ist nicht besonders sinnvoll.

        Meinetwegen nehme ich auch einen Button.

        Nimm einen Button.

        var div = document.getElementById('targetUI');
        newelement = '<li  class="selected"> <label name="' + item[0] + '" id="' + item[0] + '">' + item[1] + '</label></li>';
        

        Zu label siehe oben. Warum steht da div als Variablenbezeichner?

        
        if (div != null) {
        div.innerHTML += newelement;
        

        Das li steht für list item. Wenn es sich bei div nicht um eine ol oder ul handelt, dann ist li hier falsch, denn Listenelemente müssen Kindelemente einer Liste sein.

        Abgesehen davon produzierst du mit newelement eine globale Variable. Das möchtest du wahrscheinlich vermeiden und entweder hinter die Deklaration von div ein Komma setzen, oder die nächste Zeile mit einem var anfangen.

        Wenn du einen Transpiler wie Babel benutzt, kannst du übrigens auf die Stringkonkatenation mit dem überladenen Plusoperator verzichten und statt dessen Templateliterale verwenden. Zu dem Thema habe ich erst kürzlich was geschrieben.

        var elementname = '\"' + item[0] + '\"';
        var myelement= div.getElementsByTagName(elementname);
        

        Was bezweckst du hiermit? Der erste Index des Arrays item soll die ID eines Elementes enthalten, nehme ich an, jedenfalls weist du den Wert oben den Attributen name und id zu.

        Damit rufst du dann die Methode getElementsByTagName auf. Das ergibt keinen Sinn. Wie der Name der Methode bereits vermuten lässt, sucht sie Elemente mit einem bestimmten tagName.

        Der Name eines Tags wäre zum Beispiel button für ein Button-Element. Wenn du das Element nicht über sein Tag sondern über seine ID referenzieren willst, ist getElementsByTagName nicht die richtige Methode. Dafür gibt es getElementById oder auch querySelector.

        Davon abgesehen, warum baust du double quotes in den String ein? Innerhalb des als Argument übergebenen Strings sollten keine Anführungszeichen stehen, sonst wirst du nicht finden wonach du suchst.

        Davon abgesehen, warum escapest du die doppelten Anführungszeichen, wenn du für das Stringliteral ohnehin einfache verwendest?

        Sofern das so vom Browser verarbeitet werden soll, kann das nicht wie gewünscht funktionieren.

        if (myelement!= null) {
        

        Die bedingte Anweisung kannst du dir sparen, denn die Bedingung ist hier immer wahr.

        Die Methode getElementsByTagName gibt grundsätzlich eine HTMLCollection zurück. Wenn keine Elemente mit dem gesuchten Tag gefunden wurden, dann eben eine leere Liste, und die ist immer ungleich null und ungleich undefined.

            AddEvent(myelement, 'click', function () { 
                setAutoComplete(item[0], '\'' + item[1] + '\'', '\'' + parent + '\'', '\'' + idField + '\'') });
             }
         }
        

        Die Funktion AddEvent ist irgendwo definiert, nehme ich an.

        Sie wird aber vermutlich als erstes Argument keine HTMLCollection erwarten, sondern ein Objekt, das die Schnittstelle EventTarget implementiert, also zum Beispiel ein Element.

        Du musst übrigens nicht innerHTML verwenden, um neue Elemente zu erzeugen. Du kannst auch mit document.createElement('button') einen Button erzeugen, dem die gewünschten Eigenschaften hinzufügen und ihn dann beispielsweise mit appendChild einem anderen Element als Kind zuweisen.

        const button = document.createElement('button');
        button.type = 'button';
        button.textContent = item[1];
        button.id = item[0];
        
        //...
        
        div.appendChild(button);
        
        button.addEventListener('click', /* ... */);
        

        Hierbei könntest du dir dann die Referenzierung aus dem DOM sparen, denn eine Referenz bekommst du ja schon von createElement zurück.

        Viele Grüße,

        Orlok

        1. Hi,

          var div = document.getElementById('targetUI');
          newelement = '<li  class="selected"> <label name="' + item[0] + '" id="' + item[0] + '">' + item[1] + '</label></li>';
          

          Zu label siehe oben. Warum steht da div als Variablenbezeichner?

          weil das Ding, in dem sich die Liste befindet, die auch ein <ul> hat, (das du hier nicht sehen kannst, weil ich den Code weggelassen habe) ein Div ist.

          Abgesehen davon produzierst du mit newelement eine globale Variable. Das möchtest du wahrscheinlich vermeiden und entweder hinter die Deklaration von div ein Komma setzen, oder die nächste Zeile mit einem var anfangen.

          Richtig, habs schlichtweg vergessen zu hinzuschreiben. Danke.

          Wenn du einen Transpiler wie Babel benutzt, kannst du übrigens auf die Stringkonkatenation mit dem überladenen Plusoperator verzichten und statt dessen Templateliterale verwenden. Zu dem Thema habe ich erst kürzlich was geschrieben.

          var elementname = '\"' + item[0] + '\"';
          var myelement= div.getElementsByTagName(elementname);
          

          Was bezweckst du hiermit? Der erste Index des Arrays item soll die ID eines Elementes enthalten, nehme ich an, jedenfalls weist du den Wert oben den Attributen name und id zu.

          ja, nachdem id und document.getElementyById(elementname) nicht funktioniert hat, hab ich ein div.getElementsByTagName(elementname) draus gemacht.

          Damit rufst du dann die Methode getElementsByTagName auf. Das ergibt keinen Sinn. Wie der Name der Methode bereits vermuten lässt, sucht sie Elemente mit einem bestimmten tagName.

          Jo, das macht in der Tat keinen Sinn. Wie gesagt getElementById hat nicht funktioniert. Ich hab auch das "Tag" von dem Teil überlesen. Es sollte eigentlich getElementsByName heißen.

          Davon abgesehen, warum baust du double quotes in den String ein? Innerhalb des als Argument übergebenen Strings sollten keine Anführungszeichen stehen, sonst wirst du nicht finden wonach du suchst.

          Reine Unsicherheit ... der Inhalt ist eine Zahl, ich war mir nicht sicher, was der Javascript Compiler daraus macht. Manchmal eben genau das. Eine Zahl, wo es ein String sein soll.

          Sofern das so vom Browser verarbeitet werden soll, kann das nicht wie gewünscht funktionieren.

          if (myelement!= null) {
          

          Die bedingte Anweisung kannst du dir sparen, denn die Bedingung ist hier immer wahr.

          In diesem Fall mag das sein, aber das war nicht immer so. Sie ist ein Überbleibsel als da noch GetElementById stand, damit wurde kein Element zurückgegeben. myelement war mit GetElementById null.

              AddEvent(myelement, 'click', function () { 
                  setAutoComplete(item[0], '\'' + item[1] + '\'', '\'' + parent + '\'', '\'' + idField + '\'') });
               }
           }
          

          Die Funktion AddEvent ist irgendwo definiert, nehme ich an.

          Sie wird aber vermutlich als erstes Argument keine HTMLCollection erwarten, sondern ein Objekt, das die Schnittstelle EventTarget implementiert, also zum Beispiel ein Element.

          Du musst übrigens nicht innerHTML verwenden, um neue Elemente zu erzeugen. Du kannst auch mit document.createElement('button') einen Button erzeugen, dem die gewünschten Eigenschaften hinzufügen und ihn dann beispielsweise mit appendChild einem anderen Element als Kind zuweisen.

          const button = document.createElement('button');
          button.type = 'button';
          button.textContent = item[1];
          button.id = item[0];
          
          //...
          
          div.appendChild(button);
          
          button.addEventListener('click', /* ... */);
          

          Ja, das ist schön, aber als Konstante für eine Schleife? Hattest du einen besonderen Anlass, die Elemente hier als Konstante zu deklarieren?

          viele Grüße apfelsine

          1. Hey

            Zu label siehe oben. Warum steht da div als Variablenbezeichner?

            weil das Ding, in dem sich die Liste befindet, die auch ein <ul> hat, (das du hier nicht sehen kannst, weil ich den Code weggelassen habe) ein Div ist.

            Das heißt, ul ist ein Kindelement des referenzierten divs. Oder heißt es, dass in der Variable mit dem Bezeichner div eigentlich eine ul drin ist?

            Sofern der Wert der Variable div eine Referenz auf ein gleichnamiges Element ist, führt deine Zuweisung mittels innerHTML dazu, dass li nach dem ul als Kind des div Elements eingefügt wird, und nicht als Kind der Liste. Das wäre ein Fehler.

            Wenn die Variable tatsächlich eine Referenz auf die ul enthält und nicht auf das div, solltest du wohl besser einen anderen Bezeichner für die Variable verwenden. ;-)

            nachdem id und document.getElementyById(elementname) nicht funktioniert hat, hab ich ein div.getElementsByTagName(elementname) draus gemacht.

            Was hast du dir davon versprochen?

            Wie gesagt getElementById hat nicht funktioniert.

            Dann hätte ich erstmal versucht herauszufinden, warum getElementById nicht funktioniert. Zum Beispiel hätte ich mit einem console.log(elementname) eine Kontrollausgabe gemacht und in der Konsole des Browsers nachgesehen, was tatsächlich in der Variable drin ist.

            Hättest du das gemacht, wäre dir aufgefallen, dass da was nicht stimmt.

            Ich hab auch das "Tag" von dem Teil überlesen. Es sollte eigentlich getElementsByName heißen.

            Das hätte es nicht besser gemacht. Abgesehen vom bereits gesagten, hätte ein solcher Aufruf dein Script mit einem Typfehler terminiert. Die Methode getElementsByName wird nämlich nicht von Elementen implementiert, sondern nur vom Dokumentobjekt.

            Davon abgesehen, warum baust du double quotes in den String ein? Innerhalb des als Argument übergebenen Strings sollten keine Anführungszeichen stehen, sonst wirst du nicht finden wonach du suchst.

            Reine Unsicherheit ... der Inhalt ist eine Zahl, ich war mir nicht sicher, was der Javascript Compiler daraus macht. Manchmal eben genau das. Eine Zahl, wo es ein String sein soll.

            Die Methode getElementById erwartet tatsächlich einen String, aber du kannst auch eine Zahl übergeben. Dann wird implizit die auf Number.prototype definierte Methode toString aufgerufen und die Zahl in eine Zeichenkette umgewandelt.

            Du kannst aber auch explizit casten indem du String als Funktion aufrufst.

            Wenn du für die Konkatenation von Strings den Plusoperator verwendest, dann werden Ausdrücke die zu einem anderen Datentyp aufgelöst werden grundsätzlich in Strings umgewandelt. Einzige Ausnahme von der Regel sind Symbole, in anderen Sprachen auch als Atoms bekannt.

            if (myelement!= null) {
            

            Die bedingte Anweisung kannst du dir sparen, denn die Bedingung ist hier immer wahr.

            In diesem Fall mag das sein, aber das war nicht immer so. Sie ist ein Überbleibsel als da noch GetElementById stand, damit wurde kein Element zurückgegeben. myelement war mit GetElementById null.

            Beachten: getElementById mit kleinem g. ;-) Ja, der Rückgabewert dieser Methode ist nullable. Es wäre allerdings sehr von Vorteil, wenn du das nächste Mal, wenn du hier Code postest, vorher nochmal drübergehst. Denn sonst beschäftigen wir uns hier gegebenenfalls mit Fehlern die eigentlich gar keine sind.

            const button = document.createElement('button');
            

            Ja, das ist schön, aber als Konstante für eine Schleife? Hattest du einen besonderen Anlass, die Elemente hier als Konstante zu deklarieren?

            Wenn man modernes JavaScript schreibt, ist es üblich const zu verwenden, wenn die Bindung zwischen Bezeichner und Wert für die Lebenszeit der Variable konstant bleiben soll, also nicht beabsichtigt ist, der Variable später einen anderen Wert zuzuweisen.

            Für var gibt es heute eigentlich kaum noch Anwendungsfälle. Wenn eine Konstante aus oben genanntem Grund nicht das Richtige ist, dann würde man die Variable mit let deklarieren.

            Variablen die mit var deklariert werden sind immer funktionsweit sichtbar. const und let hingegen besitzen Blockscope. Da es gute Praxis ist, Variablen so lokal wie möglich zu deklarieren, sind const und let hier klar im Vorteil.

            for (var index = 0; index < 5; index++) {
              var number = 42;
            }
            
            console.log(index, number); // 5, 42
            

            Wenn du wie hier var verwendest, dann existieren die im Schleifenkopf und Scheifenkörper deklarierten Variablen nach der Abarbeitung der Schleife weiter.

            for (let index = 0; index < 5; index++) {
              const number = 42;
            }
            
            console.log(index, number); // Reference Error
            

            Hier sind die Variable index und die Konstante number an die lexikalische Umgebung des Anweisungsblocks der Schleife gebunden. Der Versuch des Zugriffs außerhalb der Schleife erzeugt eine Ausnahme. Die Konstante number wird hier in jeder Iteration neu initialisiert.

            In anderen Sprachen ist es üblich, dass Konstanten etwa nur global deklariert werden können, oder dass ihnen lediglich zur Compilezeit bekannte Werte zugewiesen werden dürfen. Das ist in JavaScript nicht der Fall.

            Einer mit const deklarierten Konstante muss bei ihrer Deklaration ein Wert zugewiesen werden, aber konstant ist hier tatsächlich nur die Bindung von Name und Wert. Wenn statt einem skalaren Wert ein Objekt zugewiesen wird, also mithin auch eine Datenstruktur wie ein Array, kann dieses Objekt nach wie vor verändert werden.

            Soll auch ein referenziertes Objekt immutable, also unveränderlich gemacht werden, dann müsste dies explizit angefordert werden, etwa mit der Methode freeze des Konstruktors Object.

            Die Deklaration mittels var besitzt einige Quirks, die unter Umständen zu schwer auffindbaren Fehlern im Programm führen können. So sind zum Beispiel Mehrfachdeklarationen in der selben lexikalischen Umgebung mit var ohne weiteres möglich. Ebenso die Referenzierung der Variable vor ihrer Deklaration.

            Solche potentiell fehlerträchtigen Praktiken sind bei der Verwendung von const und let von vorneherein ausgeschlossen, weswegen man grundsätzlich diese Keywords für die Deklaration von Variablen und Konstanten verwenden sollte.

            Sowohl const als auch let werden mittlerweile von den allermeisten Browsern unterstützt. Allerdings kann es nicht schaden, sich vor der Verwendung im Produktiveinsatz nochmal zu informieren, ob alle Browser die man berücksichtigen will, oder muss, die Syntax beherrschen.

            Aber das gilt natürlch nur, sofern man den Code vor der Auslieferung nicht ohnehin in ein kompatibles Format übersetzen lässt.

            Viele Grüße,

            Orlok

        2. Hallo nochmal,

          also ich habe jetzt einige Änderungen vorgenommen und mein Event wird immer überschrieben, es übergibt nur einen Wert an setAutoComplete. Nämlich den letzten aus der Iteration.

          $.each(msg, function (i, value) {
              item = value.split(";");
                                                  
                  try{
                      
                                                          
                      var div = document.getElementById('targetUI');
                      //create new listelement for station and mark as selected
                      var li = document.createElement('li');
                      li.type = 'li';
                      li.className = 'selected';
                                                      
                      //create button in listelement for station 
                      var button = document.createElement('button');
                      button.type = 'button';
                      button.textContent = item[1];
                      button.id = item[0];
                      if (i == 0) {
                          button.className = 'dropdownelement';
                      }
          
                      //add button to listelement
                      li.appendChild(button);
                   
                                                      
                      if (div != null) {
                          //append to list-node previously added before iteration
                          div.appendChild(li);
                          //AddEvent(button, 'click', function () { setAutoComplete(item[0], item[1], parent, idField) });
                          button.addEventListener('click', function () { setAutoComplete(item[0], item[1], parent, idField) });
          
                          //button.addEventListener('click', function () { setAutoComplete(fcn) });
          
                         
                      }
                  }
                  catch(e)
                  {
                      alert("Fehler: " + e.message);
                  }
                                                     
             
          }); // end each iteration
          
          1. Hey

            also ich habe jetzt einige Änderungen vorgenommen und mein Event wird immer überschrieben, es übergibt nur einen Wert an setAutoComplete. Nämlich den letzten aus der Iteration.

            Und das wundert dich? ;-)

            $.each(msg, function (i, value) {
            

            Zunächst mal wäre zu erwähnen, dass es zwar grundsätzlich sinnvoll ist, wenn man schon ein Framework wie jQuery einbindet, sich auch dessen Methoden zu bedienen, aber von jeder Regel gibt es Ausnahmen.

            Hier die generische Methode each des jQuery-Objektes zu verwenden ist nicht falsch, aber auch nicht wirklich sinnvoll. Zumindest, sofern es sich bei dem Wert von msg um ein iterierbares Objekt handelt, also zum Beispiel um ein gewöhnliches Array.

            Sollte dies der Fall sein, wäre die native Methode forEach vorzuziehen, welche direkt auf jeder Arrayinstanz aufgerufen werden kann.

            msg.forEach(function (value, index /* array */) {
            
              // do something
            
            });
            

            Beachte, dass hier die Reihenfolge der Argumente, mit denen die Callback-Funktion aufgerufen wird anders herum ist als bei der Methode each, also erst der aktuelle Wert und dann der Index.

            Als drittes Argument wird darüber hinaus noch eine Referenz auf das Array übergeben, über welches iteriert wird. Aber die brauchst du hier nicht, also kann man sich die Deklaration eines dritten Parameters in diesem Fall sparen.

            item = value.split(";");
            

            An dieser Stelle liegt die Ursache für das von dir beschriebene Problem.

            button.addEventListener('click', function () {
              setAutoComplete(item[0], item[1], parent, idField)
            });
            

            Was glaubst du passiert, wenn diese Funktion aufgerufen wird?

            In diesem Fall wird versucht, die Referenz mit dem Bezeichner item aufzulösen, was innerhalb dieser Funktion nicht möglich ist, da weder ein Parameter noch eine lokale Variable mit diesem Bezeichner deklariert wurde.

            Da du in der äußeren lexikalischen Umgebung der Handlerfunktion, also der an each übergebenen Rückruffunktion, wie gesehen ebenfalls keine Variable mit dem Bezeichner item deklariert hast, sondern lediglich eine Variable in einem umgebenden Gültigkeitsbereich referenzierst, wird entsprechend dort weitergesucht.

            Schließlich wird von jeder Handlerfunktion, die du innerhalb der an each übergebenen Callback-Funktion definierst, ein und dieselbe Variable referenziert, und da die Eventhandler erst ausgeführt werden, wenn die Iteration abgeschlossen ist, wird entsprechend der Wert zurückgegeben, welcher der Variable item zuletzt zugewiesen wurde.

            var item = value.split(';');
            

            Was du also eigentlich möchtest, ist bei jedem Aufruf der an each übergebenen Funktion eine lokale Variable anzulegen, sodass der Wert in der Closure, also dem Funktionsabschluss konserviert wird.

            try{
              //..
            }
            catch(e)
            {
              alert("Fehler: " + e.message);
            }
            

            Ich würde mich für einen Klammerstil entscheiden. Es fördert nicht unbedingt die Lesbarkeit des Codes, wenn man das mal so und mal so macht. Davon abgesehen scheint mir try und catch an dieser Stelle ziemlich überflüssig.

            Hier kann eigentlich nur dann ein Fehler auftreten, wenn in der Variable div kein Objekt ist, dass die Methode appendChild implementiert, und hier prüfst du immerhin gegen null und undefined.

            Sollte das Statement und der Aufruf von alert dem Debugging dienen, dann möchte ich noch hinzufügen, dass dies nicht der richtige Ansatz ist. Hierfür solltest du die Entwicklerwerkzeuge deines Browsers verwenden. Dort werden dir in der Konsole Fehler angezeigt, üblicherweise mit Typ, Message, Stacktrace, Script und Zeilennummer.

            Über die console API stehen dir verschiedene Methoden zur Verfügung, um Kontrollausgaben in der Konsole des Browsers zu machen. Unter anderem log für einfache Kontrollausgaben, dir für Inspektionen, warn für Warnungen, error für eigene Fehlermeldungen, info für zusätzliche Informationen und assert für Fehlermeldungen, wenn eine bestimmte Annahme nicht zutrifft.

            const foo = null;
            
            console.assert(foo === 'bar', 'foo is not bar');
            

            Das ergibt einen Fehler, Assertion failed. Darüber hinaus kannst du im Script mit dem debugger-Statement auch Breakpoints setzen, an denen dein Programm angehalten werden soll. Dann kannst du die verschiedenen Variablen und die Werte die zu einem bestimmten Zeitpunkt mit ihnen verknüpft sind im Debugger des Browsers inspizieren.

            var div = document.getElementById('targetUI');
            
            if (div != null) {
              div.appendChild(li);
            

            Das hatte ich in meiner anderen Antwort ja schon angesprochen. Es ist extrem verwirrend, wenn du eine Variable div nennst, die eigentlich eine ul referenziert. Das ist nicht nachvollziehbar und sollte geändert werden. Davon abgesehen verwendest du jQuery, also kannst du dir den Aufruf der Methode getElementById hier sparen und einfach $('#targetUI') schreiben.

            const $targetUI = $('#targetUI');
            
            if ($targetUI.length) {
            

            Wenn es kein Element mit der ID targetUI gibt, wird von jQuery ein leeres Objekt zurückgegeben. Du kannst also wie in dem Beispiel oben auf die Existenz prüfen. Ich habe hier dem Namen der Konstante das Prefix $ vorangestellt, um zu verdeutlichen, dass hier ein jQuery-Objekt und nicht direkt ein Element referenziert wird, aber das kannst du natürlich halten wie du willst.

                        //create new listelement for station and mark as selected
                        var li = document.createElement('li');
                        li.type = 'li';
                        li.className = 'selected';
                                                        
                        //create button in listelement for station 
                        var button = document.createElement('button');
                        button.type = 'button';
                        button.textContent = item[1];
                        button.id = item[0];
                        if (i == 0) {
                            button.className = 'dropdownelement';
                        }
            
                        //add button to listelement
                        li.appendChild(button);
            

            Auch hierfür wären entsprechende jQuery-Methoden zu verwenden, wenn du dieses Framework schon einbindest. Allerdings ist nicht alles was du hier tust sinnvoll.

            li.type = 'li';
            

            Das ergibt zum Beispiel keinen Sinn, denn li hat kein type-Attribut.

            Darüber hinaus solltest du beachten, dass die Vergabe einer Klasse selected nicht dazu führt, dass Benutzer assistiver Software über den Zustand deines Widgets in Kenntnis gesetzt werden. Hier wirst also noch etwas Arbeit investieren müssen, wenn das Ganze zugänglich sein soll.

            Viele Grüße,

            Orlok

            1. Hi

              also ich habe jetzt einige Änderungen vorgenommen und mein Event wird immer überschrieben, es übergibt nur einen Wert an setAutoComplete. Nämlich den letzten aus der Iteration.

              Und das wundert dich? ;-)

              Nein nicht wirklich. Was man halt so tut, wenn man sich durchhangelt.

              Als drittes Argument wird darüber hinaus noch eine Referenz auf das Array übergeben, über welches iteriert wird. Aber die brauchst du hier nicht, also kann man sich die Deklaration eines dritten Parameters in diesem Fall sparen.

              item = value.split(";");
              

              An dieser Stelle liegt die Ursache für das von dir beschriebene Problem.

              button.addEventListener('click', function () {
                setAutoComplete(item[0], item[1], parent, idField)
              });
              

              Was glaubst du passiert, wenn diese Funktion aufgerufen wird?

              Meine Funktion tanzt Samba?...

              Schließlich wird von jeder Handlerfunktion, die du innerhalb der an each übergebenen Callback-Funktion definierst, ein und dieselbe Variable referenziert, und da die Eventhandler erst ausgeführt werden, wenn die Iteration abgeschlossen ist, wird entsprechend der Wert zurückgegeben, welcher der Variable item zuletzt zugewiesen wurde.

              Scherz beiseite, tja, das macht Sinn. Das führt mich dann wieder zu meiner Stringlösung zurück…

              var item = value.split(';');
              

              Was du also eigentlich möchtest, ist bei jedem Aufruf der an each übergebenen Funktion eine lokale Variable anzulegen, sodass der Wert in der Closure, also dem Funktionsabschluss konserviert wird.

              und das soll dann funktionieren...? ich werde es ausprobieren.

              Ich würde mich für einen Klammerstil entscheiden. Es fördert nicht unbedingt die Lesbarkeit des Codes, wenn man das mal so und mal so macht. Davon abgesehen scheint mir try und catch an dieser Stelle ziemlich überflüssig.

              Mag sein, aber nicht, wenn ich ständig dran rumbastel. Ich finde die Browserkonsole auch nicht sehr benutzerfreundlich und ehrlichgesagt in Teilen ziemlich umständlich in der Handhabung sodass ich manchmal am liebsten in den Bildschirm greifen würde. Für einfache Sachen reicht mir das Alert.

              Darüber hinaus kannst du im Script mit dem debugger-Statement auch Breakpoints setzen, an denen dein Programm angehalten werden soll.

              Dann kannst du die verschiedenen Variablen und die Werte die zu einem bestimmten Zeitpunkt mit ihnen verknüpft sind im Debugger des Browsers inspizieren.

              Das ist mir bekannt.

              var div = document.getElementById('targetUI');
              
              if (div != null) {
                div.appendChild(li);
              

              Das hatte ich in meiner anderen Antwort ja schon angesprochen. Es ist extrem verwirrend, wenn du eine Variable div nennst, die eigentlich eine ul referenziert. Das ist nicht nachvollziehbar und sollte geändert werden.

              Nein, weil du den Code vorher eben nicht kennst. Und targetUI IST ein DIV, an das ein Kindelement UL angehängt wird. Dieser Abschnitt wäre normalerweise ausserhalb der Schleife. Der muss nur einmal ausgeführt werden. Ich habe auch keine Lust über Sinnhaftigkeiten von Variablennamen zu diskutieren, wenn sie nicht gerade ein geschützter Begriff sind und damit die Funktionsweise beeinträchtigen würden.

                          //create new listelement for station and mark as selected
                          var li = document.createElement('li');
                          li.type = 'li';
                          if (i == 0) {
              							li.className = 'selected';
                          }                                
                          //create button in listelement for station 
                          var button = document.createElement('button');
                          button.type = 'button';
                          button.textContent = item[1];
                          button.id = item[0];
                          //if (i == 0) { //falscher Platz
                              button.className = 'dropdownelement';
                          //}
              
                          //add button to listelement
                          li.appendChild(button);
              

              Auch hierfür wären entsprechende jQuery-Methoden zu verwenden, wenn du dieses Framework schon einbindest. Allerdings ist nicht alles was du hier tust sinnvoll.

              Das kannst du aus meiner Perspektive nicht beurteilen. Du siehst nur einen Ausschnitt von einem Prozess. Die Historie, warum was wie so steht wie es ist, mag für mich sinnvoll gewesen sein zu diesem Zeitpunkt. Und wie ich bereits erwähnt habe, möchte ich jQuery so wenig wie möglich verwenden. Es ist drin, ob ich es nutze oder nicht. Ich habe keinen Bock mehr das es mir beim nächsten Update wieder was zerschießt. Kann ich zwar trotzdem nicht ausschließen aber na ja.

              li.type = 'li';
              

              Das ergibt zum Beispiel keinen Sinn, denn li hat kein type-Attribut.

              Darüber hinaus solltest du beachten, dass die Vergabe einer Klasse selected nicht dazu führt, dass Benutzer assistiver Software

              Assistiver Software??? Meinst du einen Debugger??

              über den Zustand deines Widgets in Kenntnis gesetzt werden. Hier wirst also noch etwas Arbeit investieren müssen, wenn das Ganze zugänglich sein soll.

              nun - ohne die Dokumentation zu wälzen habe ich einfach mal angenommen, das ich meinen Stylesheet "selected" da in class unterbringen kann. Mir ist gestern dazu nichts falsches beim testen aufgefallen. Allerdings habe ich das If an einen sinnfreien Ort gesetzt, es sollte eigentlich bei "selected" sein. Der Type bei li macht in der Tat keinen Sinn.

              Danke für die Unterstützung!

              apfelsine

              1. Hallo apfelsine,

                Darüber hinaus solltest du beachten, dass die Vergabe einer Klasse selected nicht dazu führt, dass Benutzer assistiver Software

                Assistiver Software??? Meinst du einen Debugger??

                Nein. Beispielsweise ein Screenreader.

                über den Zustand deines Widgets in Kenntnis gesetzt werden. Hier wirst also noch etwas Arbeit investieren müssen, wenn das Ganze zugänglich sein soll.

                nun - ohne die Dokumentation zu wälzen habe ich einfach mal angenommen, das ich meinen Stylesheet "selected" da in class unterbringen kann. Mir ist gestern dazu nichts falsches beim testen aufgefallen.

                Hast du auch ausprobiert, ob du das nur mit der Tastatur – also komplett ohne Maus – bedienen kannst? Funktioniert es auch auf Touchscreens?

                Gruß
                Julius

      2. Der Fehler der da ein Fehler gewesen sein sollte, ist kein Fehler mehr,

        wenn auch viele andere Dinge ein Fehler gewesen sein mögen.

      3. @@apfelsine

        Irgendwo habe ich gelesen A wäre nicht gut für onclick.

        Das kann man so pauschal nicht sagen. Evangelina Ferreira gibt in ihrem Artikel 10 guidelines to improve your web accessibility, Abschnitt 6. Use the right mark-up unter „Button vs. <a> tag“ gute Hinweise, wann Buttons und wann Links zu verwenden sind.

        Meist will man mit click-Events Aktionen auf einer Seite auslösen; also Buttons verwenden.

        Im nachfolgenden Abschnitt 7. Use roles when necessary gibt es aber ein Beispiel, wo ein click-Event für ein a-Element sinnvoll ist – mit role="button". Siehe dazu auch meinen Kommentar.

        LLAP 🖖

        --
        “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
  4. Nur mal so nebenbei bemerkt und zusätzlich zu dem, was Gunnar bereits sagte …

    <li onclick="javascript:setAutoComplete()">
    

    Du könntest hier auch folgendes schreiben:

    <li onclick="php:setAutoComplete()">
    

    Das funktioniert. Magic!

    Jedenfalls habe ich den Verdacht, dass du nicht wirklich weißt, was du hier tust, denn anders kann ich mir die Verwendung dieser Syntax an dieser Stelle nicht erklären.

    Was du hier verwendest ist ein sogenanntes Labelled Statement, welches sich zusammensetzt aus einem Bezeichner für das Label, einem Doppelpunkt sowie einem weiteren Statement. Dieses Konstrukt wird selten verwendet und wenn, dann meist im Zusammenhang mit verschachtelten Schleifen.

    outerLoop:
    for (let i = 0; i < 5; i++) {
    
      innerLoop:
      for (let j = 0; j < 5; j++) {
    
        if (condition) {
          continue outerLoop;
        }
    
      }
    
    }
    

    Indem man den Schleifen durch das Label einen Namen zuweist, kann man mit den Statements break und continue steuern, welche Schleife abgebrochen oder fortgesetzt werden soll.

    Die einzige weitere halbwegs sinnvolle Anwendung für ein Label ist in Verbindung mit Blöcken für Anweisungen, denen ebenfalls auf diese Art ein Name zugewiesen werden kann. Hier kann die weitere Ausführung eines Anweisungsblocks mit break unterbunden werden.

    outerBlock: {
    
      innerBlock: {
    
        if (condition) {
          break outerBlock;
        }
    
      }
    
    }
    

    Das führt allerdings zu schlecht lesbarem Code und wird daher fast nie verwendet.

    Wie anfangs erwähnt, kann hinter dem Doppelpunkt jedoch irgendein Statement stehen, dass heißt, ein Label kann nicht nur auf die zuvor beschriebenen Arten verwendet werden, sondern zum Beispiel auch zusammen mit einer Call Expression, also einem Funktionsaufruf.

    Eben so, wie du das in deinem Beispielcode mit dem Label javascript machst:

    javascript:setAutoComplete()
    

    Das erzeugt aus genanntem Grund keinen Syntaxfehler, ist aber natürlich vollkommen sinnfrei, denn das Label kann von nirgendwo referenziert werden, und selbst wenn, könnte man nichts damit anfangen.

    Auch als Annotation wäre es ziemlich überflüssig, denn was für Code sollte an dieser Stelle denn sonst ausgeführt werden?

    Naja, genau genommen sollte an dieser Stelle überhaupt kein Code ausgeführt werden.

    Eventhandler über Attribute zu registrieren ist ziemlich schlechte Praxis. Markup und Scriptcode sollte nicht miteinander vermischt werden, ebensowenig wie HTML und CSS, denn das führt zu schlecht les- und wartbarem Code.

    Registriere deine Eventhandler im Script und verwende hierzu die auf allen Elementen sowie einigen anderen Objekten definierte Methode addEventListener, oder, wenn du ohnehin jQuery einbindest, die von diesem Framework bereitgestellten Methoden.

    document.querySelector('button').addEventListener('click', function (event) {
    
      setAutoComplete(...);
    
    });
    

    Die Methode addEventListener erwartet als erstes Argument einen String mit dem Typ des Ereignisses, hier also click, ohne das Prefix on, und als zweites Argument die Funktion die beim Eintritt des Ereignisses aufgerufen werden soll.

    $('button').click(function (event) {
    
      setAutoComplete(...);
    
    });
    

    jQuery bietet für das Event click sogar eine eigene Methode an. Es ist also nichtmal nötig die Methode on zu bemühen.

    Solltest du dich für eine JavaScript-Lösung entscheiden, dann hoffentlich auch dafür, interaktive Elemente wie Buttons zu verwenden, damit deine Seite auch von solchen Benutzern verwendet werden kann, die auf eine funktionierende Tastaturbedienung angewiesen sind.

    Wenn du das machst, dann brauchst du dich auch nicht um das Abfangen von Tastaturevents wie zum Beispiel keydown zu kümmern, denn wenn ein interaktives Element durch eine Tastatureingabe aktiviert wird, dann wird auch ein click Event ausgelöst.

    Aber vielleicht brauchst du hier ja auch gar kein JavaScript.

    1. Danke für deinen Input.

      Ich habe hier zusammenfassend geantwortet: https://forum.selfhtml.org/self/2017/aug/15/select-li-element-on-keyup/1702098#m1702098