Orlok: Select Li Element on Keyup

Beitrag lesen

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