Klaus: Jquery UI Autocomplete / Selektion von Elementen

Hallo,

Nachdem es mir gelungen ist, die Jquery UI Autocomplete Funktion isoliert zum arbeiten zu bringen, möchte ich sie gerne in ein laufendes Formular integrieren.

Mein JS-Code (der isoliert gut arbeitet):

  
$(function() {  
            // $('#abbrev').val(\"\");  
            $(\"#state\").autocomplete({  
                source: \"./_new/auto.php\",  
				 focus: function( event, ui ) {  
                 $( \"#state\" ).val( ui.item.label_unformatiert );  
                 $( \"li\" ).css( 'cursor', 'pointer' );  
                 return false;  
                 },  
                minLength: 4,  
                select: function(event, ui) {  
                    $('#hidden_id').val(ui.item.id);  
                    $('#abbrev').val(ui.item.abbrev);  
                    $('#nik1').val(ui.item.nik1);  
  
                }  
            })  
			  
            .data(\"autocomplete\")._renderItem = function( ul, item ) {  
			 item.label_unformatiert = item.label;  
			 item.label = item.label.replace(new RegExp(\"(?![^&;]+;)(?!<[^<>]*)(\" + $.ui.autocomplete.escapeRegex(this.term) + \")(?![^<>]*>)(?![^&;]+;)\", \"gi\"), \"<span class='blaub'>$1</span>\");  
             return $( \"<li></li>\" )  
            .append( \"<a><b>\" + item.label + \"</b><br>\" + item.bemerkung + item.taferint + \"</a><hr size=1>\" )  
            .appendTo( ul );  
             };  
        });  

Und das Formular:

  
  
<input type="text" id="state"  name="nummer" size='50' /><br>  
<input type="text" id="abbrev" name="bezeichnung" size="80"/><br>  
<input type="text" id="nik1" name="einheit" size="80"/><br>  
<input type="hidden" id="hidden_id" name="ID" />  

Mein Json codiertes return array besteht aus Datensätzen mit je:

$row_array['id'], $row_array['label'], $row_array['bemerkung'], $row_array['value'], $row_array['abbrev'] , $row_array['nik1'], $row_array['taferint']

Hierzu gleich eine Frage:
Warum wird die Nummer (die steht in $row_array['value']) aus dem JSON Array tatsächlich in das #state Element eingetragen, obwohl ich doch gar nicht  $('#state').val(ui.item.value); notiert habe??

Nun zu meinem eigentlichen Problem:

In meinem laufenden Script, in das ich Jquery UI autocomplete integrieren möchte, generiere ich mehrere "Eingabezeilen" per php nach folgendem Muster:

  
...  
<TD>  
<input type='text' class='f_tab' name=\"nummer[$i]\" id=\"nummer[$i]\" \>  
</TD>  
<TD>  
<input type='text' class='f_tab' name=\"bezeichnung[$i]\" id=\"bezeichnung[$i]\" />  
</TD>  
...  

(Die Tabelle ist eine echte Tabelle, sie dient nicht der Formatierung, sondern ist eine echte Aufzählung)

Meine Fragen:

1. Ist es sinnvoll, den JS-Code für jede Zeile zu wiederholen? Falls ja, wo kommt er hin? In Zelle 1 jeder Zeile?

2. Kann man das über ein Konstrukt ala jQuery(’input[id^="..."]’) einfangen?

3. Kann mir einer das ".data("autocomplete")._renderItem =" erklären? Also nicht den Inhalt der nachfolgenden Funktion, die ist mir durchaus klar.
 -- Warum der Punkt vor dem "data"?
 -- Warum data?
 -- Warum "autocomplete"

Gruß, Klaus

  1. Hallo!

    1. Ist es sinnvoll, den JS-Code für jede Zeile zu wiederholen?

    Nein. JavaScript-Code solltest du nicht mit PHP generieren, schon gar nicht denselben Code immer wieder. Notiere ihn besser einmal in einer externen Datei gemäß dem Paradigma »Unobtrusive JavaScript«. Schreibe den JavaScript-Code dann so flexibel, dass er mehrfach angewendet werden kann bzw. sich automatisch auf verschiedene Elemente im DOM anwendet.

    Was du mit PHP generieren solltest, ist HTML-Markup und ggf. JSON. Im HTML lassen sich üblicherweise alle Infos unterbringen, die das JavaScript benötigt.

    (Das sind keine ewigen Wahrheiten, sondern Faustregeln, die einem helfen, gut strukturierten Code zu schreiben.)

    1. Kann man das über ein Konstrukt ala jQuery(’input[id^="..."]’) einfangen?

    Im Prinzip ja, das ist einer der Schritte, um den Code wiederverwendbar zu machen.

    Arbeite mit einem passenden Selektor, z.B. mit Klassen und dem Klassenselektor. Von einem Element aus kannst du andere, zugehörige finden:

    http://api.jquery.com/find/
    http://api.jquery.com/parents/
    http://api.jquery.com/siblings/

    1. Kann mir einer das ".data("autocomplete")._renderItem =" erklären?

    .data('autocomplete') liefert die Instanz von jQuery UI Autocomplete.

    Diese hat (bzw. erbt) wohl eine Methode namens _renderItem. Diese Methode wird hier überschrieben.

    -- Warum der Punkt vor dem "data"?

    Der Punkt ist der Operator zum Zugriff auf Objekteigenschaften. Schema:

    objekt.eigenschaft

    Wertzuweisung:

    objekt.eigenschaft = wert

    -- Warum data?

    Das ist die data-Funktion von jQuery. So kommst du an JavaScript-Werte, die an dem Element gespeichert sind. Das macht jQuery UI mit der Autocomplete-Instanz.

    -- Warum "autocomplete"

    Das ist einfach der Name, unter dem die jQuery-UI-Autocomplete-Instanz intern gespeichert ist.

    (Bei der aktuellen Version von jQuery UI muss ich übrigens .data('uiAutocomplete') schreiben. Getestet hier.)

    Mathias

    1. Hallo Mathias,

      danke für Deine Antwort. Leider komme ich nicht wirklich weiter mit ihr.

      Mein Problem und wie ich es gerne angehen würde.

      Ich könnte die JS-Funktion allgemein nutzen, wenn ich in ihr ermitteln könnte, welchen (php!) Arrayindex ich gerade bearbeite.

      Also aus <input type=\"text\" id=\"nummer[5]\" class='f_300' name=\"Nummer[5]\"> müßte ich in meiner JS-Funktion den php-Array-Index 5 ermitteln können, in eine Variable packen und anschließend könnte ich ihn an alle Div-Elemente der JS Funktion anhängen.

      Also als Beispiel hier Pseudocode:

      $(function() {  
      Wenn Focus im input-feld, daß mit "input-blabla" anfängt, dann packe mir alles, was hinter diesem String kommt und weder [ noch ] ist, in die Variable "test123"  
                  $("#nummer[" + test123 + "]").autocomplete({...
      

      Kann man das in dieser Art machen?

      Klaus

      1. Hallo,

        Wenn Focus im input-feld, daß mit "input-blabla" anfängt, dann packe mir alles, was hinter diesem String kommt und weder [ noch ] ist, in die Variable "test123"
                    $("#nummer[" + test123 + "]").autocomplete({...[/code]

        Ich kann mich nur wiederholen: um mehrere Elemente zu selektieren und zugehörige zu finden, sind Klassen am einfachsten. Wenn es geht, dann verwende .find('.klasse'), .parents('.klasse') oder .siblings('.klasse'), um zugehörige Elemente zu finden. Das setzt natürlich einen entsprechenden DOM-Baum voraus.

        Wenn das nicht geht, kannst du natürlich explizit die Nummer an einem Element speichern. Das geht mit HTML5-Data-Attributen:

        <input id="nummer[5]" data-nummer="5">

        Dieses Data-Attribut kannst du mit jQuery auslesen: http://api.jquery.com/data/

        var nummer = jqueryobjekt.data('nummer');

        Dann hast du schonmal die "5" und kannst darüber ein Element mit einer entsprechenden ID suchen.

        $('#andereID[' + nummer + ']')

        Man könnte es natürlich auch ohne zusätzliches Data-Attribut lösen und die Nummer aus dem id-Attribut herausfriemeln, aber so erscheint es mir am einfachsten.

        Grüße
        Mathias

        1. Hallo Mathias,

          ... kannst du natürlich explizit die Nummer an einem Element speichern. Das geht mit HTML5-Data-Attributen:

          <input id="nummer[5]" data-nummer="5">

          Das habe ich jetzt gemacht und alles funktioniert wie gewünscht.

          Vielen Dank für Deine Hilfe.

          1 Frage noch: Gibt es beim Selektieren sowas wie einen "oder-Operator"?
          Also sowas wie

          <pseudo>
          jQuery(’input[id^="..."]’) || jQuery(’input[id^="....."]’)

          </pseudo>

          Klaus

          1. Hallo!

            Gibt es beim Selektieren sowas wie einen "oder-Operator"?

            Wie in CSS kannst du die Selektoren mit einem Komma verbinden:

            $('.klasse1, .klasse2, .klasse2')  
            $('#id1, #id2, #id3')  
            $('#id1, .klasse1, h1, input[type=text], p.teaser')
            

            usw.

            Das geht mit allen möglichen Selektoren und die Selektoren sind auch beliebig kombinierbar.

            jQuery geht dann alle Selektoren durch, sucht die passenden heraus und fügt alle zur Ergebnisliste hinzu.

            Mathias

            1. Hallo Mathias,

              Wie in CSS kannst du die Selektoren mit einem Komma verbinden:

              $('.klasse1, .klasse2, .klasse2')

              $('#id1, #id2, #id3')
              $('#id1, .klasse1, h1, input[type=text], p.teaser')

              
              > usw.  
                
              Das ist gut. Ergibt bei mir eine interessante Zusatzfrage: Kann ich innerhalb der dann auszuführenden Funktion auf den Selektor nochmal zugreifen, der den event ausgelöst hatte?  
                
              Also sowas wie  
                
              $('#id1, #id2, #id3').onclick(function) {  
              var geklickte\_id = ...;  
              alert('Der Klick erfolgte über die ID' + geklickte\_id);  
              }  
                
              Klaus
              
              1. Hallo,

                Also sowas wie

                $('#id1, #id2, #id3').onclick(function) {
                var geklickte_id = ...;
                alert('Der Klick erfolgte über die ID' + geklickte_id);
                }

                Habe es schon gefunden.

                alert( $( this ).attr( 'id' ) );

                macht das.

                Klaus

                1. Hallo!

                  alert( $( this ).attr( 'id' ) );

                  Ja, oder einfach:

                  this.id

                  Es besteht hier kein zwingender Grund, das Element in ein jQuery-Objekt zu verpacken, um das ID-Attribut auszulesen. Man kann es höchstens aus Gründen der Konsistenz tun.

                  Grüße
                  Mathias

                  1. Hallo,

                    Ja, oder einfach:

                    this.id

                    Danke :)

                    Es besteht hier kein zwingender Grund, das Element in ein jQuery-Objekt zu verpacken, um das ID-Attribut auszulesen. Man kann es höchstens aus Gründen der Konsistenz tun.

                    Ist die eine Schreibweise also natives JS (aber doch auch ein Objekt, oder?) und die andere ist ein Jquery Objekt?

                    Ich habe noch eine ganz andere Frage:

                      
                    .data(\"autocomplete\")._renderItem = function( ul, item ) {  
                    ...  
                    
                    

                    Kann ich an dieser Stelle ermitteln, wie viele Items ich behandeln werde?

                    Gruß, Klaus