heinetz: JQuery ... der erste Versuch

Hallo Forum,

vor einiger Zeit habe ich daimt begonnen, mich mit dem Gedanken,
JS-Framework: Ja/Nein, Welches überhaupt?, Warum überhaupt?
... auseinanderzusetzen und eine mächtige Diskussion losgetreten.

Danke nochmal an alle Beteiligten für eine lebhafte Diskussion,
die mir sehr geholfen hat !

Jetzt kommt meine Einstieg:

Anlass für mich, mich mit dem Thema auseinanderzusetzen war
dass ich in meinem sehr umfangreichen Projekt entdeckt habe,
dass ich schonmal prototype eingebunden hatte ... und nicht
so recht wusste, wo ich das verwendet hatte. Natürlich hätte
ich das zu dem Zeitpunkt genau untersuchen können, empfand es
aber als nicht so wichtig, weil ich eh über kurz oder lang
damit konfrontiert werden würde ... und das ist jetzt passiert.

Ich hatte das Framework eingebunden, um einen Ajax.Request
umzusetzen. Ich weiss, dafür das ganze umfassende Framework
zu laden, bedeutet mit Kanonen auf Spatzen zu schiessen,
weil ich aber nicht wusste, wie ich das sonst machen sollte
und weil ich die Funktionalität eh für das Backend der Site
brauchte, spielt die LAdezeit keine grosse Rolle.

Da ich mich nach dieser Diskussion erstmal dafür entschieden
hatte, mich mit JQuery vertraut zu machen, habe ich eben die
Funktion umgeschrieben und setzen den Ajax.Request nun mit
JQuery ab, was genauso unproblematisch ging.

... und dann habe ich versucht, in meinem Skript etwas
handgeschriebes in JQuery-Systax umzuschreiben:

In einem zuvor geladenen Script Wird die Funktion
'ieinputonfocus()' onload aufgerufen. Die sorgt
dafür, dass für jedes input type="text" auf der
Site ein Event onfocus definiert wird, der onfocus
den ClassName des Input ändert, um das was FF mit:

input:focus{  
}

... für IE zu simulieren. In einem anderen, später
geladenen Skript muss onfocus bei einem Input etwas
anderes ZUSÄTZLICHES passieren. Ich dachte mir, das
müsse doch mit JQUERY recht einfach gehen und habe
mal ausprobiert diese Zeile:

formObj.elements[e].onfocus = function (){lA[this.name].className = "";}

... in JQuery-Syntax umzuschreiben:

formObj.elements[e].focus(function (){lA[this.name].className = "";});

Das funktioniert wie erwartet erstmal nicht.

Warum nicht? Ich glaube, mir fehlt ein Grundgedanke.

danke für Tipps und

beste gruesse,
hienetz

  1. Warum nicht? Ich glaube, mir fehlt ein Grundgedanke.

    Ja, irgendwie ist da nicht viel von jQuery zu sehen :)

    Du benötigst idR. einen Selektor - wie in CSS - der in der jQuery-Funktion aufgerufen wird

    z.B.
    $('input');

    damit selektierst du alle input-Element auf der Seite

    dann benötigst du einen Handler - bind() oder live() sind gut geeignet um einen anzuhängen - wenn es nur um einen handler geht, gibts auch eigene Methoden dafür. focus(), mouseover() usw

    $('input').bind(  
      'focus',  
      function() {  
      }  
    );
    

    Dann muss die Funktion noch irgendetwas tun.

    $('input').bind(  
      'focus',  
      function() {  
        $(this).addClass('focus');  
      }  
    );
    

    dein css ergänzt du dann um die Klasse focus, um damit die Pseudoklasse zu simulieren.

      
    input:focus,  
    input.focus {  
    }
    

    Nicht vergessen: wenn das Element den focus verliert, muss die Klasse natürlich wieder entfernt werden.

    1. Warum nicht? Ich glaube, mir fehlt ein Grundgedanke.

      Ja, irgendwie ist da nicht viel von jQuery zu sehen :)

      Du benötigst idR. einen Selektor - wie in CSS - der in der jQuery-Funktion aufgerufen wird

      ... langsam steig ich dahinter, wie das ganze zu verstehen ist!
      Ich vermute, der Verständnisfehler, der hinter meinem Versuch:

      formObj.elements[e].focus(function(){lA[this.name].className = "";})

      ... steckt, ist dass ich versucht habe, ein JQ-Methode auf ein
      DOM-Objekt anzuwenden. Dass das hier funktioniert, habe ich
      herausgefunden:

      $(':input').focus(function(){lA[this.name].className = "";});

      Damit wird der für die Inputs ursprünglich mal definierte
      onfocus-Event nicht mal überschrieben. Diesem kleinen
      Erfolgserlebnis folgt aber leider eine möglicherweise
      schwerwiegende Erkenntnis.

      Nochmal zurück zur Ausganssituation:

      var eA =[];  
        
      function init_form ()  
                        {//alert("init_form()");  
                         formObj = document.forms['adminForm'];  
                         for (e=0; e<formObj.elements.length; e++)  
                            {  
                            if(formObj.elements[e].type!="hidden") eA[formObj.elements[e].name] = formObj.elements[e];  
                            formObj.elements[e].onfocus = function (){lA[this.name].className = "";}  
                           }  
                         ...  
                        }  
        
      ...  
        
      
      

      Hieran probiere ich also, ob ich mit JQuery meinen Code sauberer
      und übersichtlicher hinbekomme. Und das hier:

      $(':input').focus(function(){lA[this.name].className = "";});

      ... funktionierte ja auch schon sehr gut. Mein Versuch, die erste
      Anweisung im Schleifenblock zu erstzen:

      $(':input:not(:hidden)').each(function(){eA[this.name]=this;});

      ... scheitert aber. Der Selektor scheint korrekt zu sein. Aber
      mein Umgang mit oder vielmehr mein Verständnis für globale
      Variablen scheint mir hier in die jQuere zu kommen. Ich weiss,
      globale Variablen sind evil aber ich weiss garnicht so genau
      warum und wie ich das anders machen soll ;(

      Meine Logik (verkürzt):

      1. in init_form() fülle ich das global defnierte Array 'eA' mit
      allen Form.elements die nicht vom Typ hidden sind.

      2. das ich an verschiednenen Stellen in anderen Funktionen
      beeinflusse und greife u.U. auf die Elemente zu
      (z.B. eA['title'].disabled=true)

      3. in check_form() verwende ich das u.U. veränderte globale 'eA'
      um  Inhalte vor dem Abschicken auf Richtigkeit zu prüfen.

      Jetzt frage ich mich, ob es grundsätzlich ein Fehler ist,
      das Array 'eA' zu definieren um mit mehreren Funktioneen
      darauf zuzugreifen, weil global evil ist, oder ich nur
      wissen muss, wie ich hier:

      $(':input:not(:hidden)').each(function(){eA[this.name]=this;});

      ... dafür sorge, dass jQuery weiss, dass ich das global definierte
      Array 'eA' füllen möchte.

      vielen dank für Tipps uns
      beste gruesse,
      heinetz

      1. Hi,

        formObj.elements[e].focus(function(){lA[this.name].className = "";})

        ... steckt, ist dass ich versucht habe, ein JQ-Methode auf ein
        DOM-Objekt anzuwenden.

        richtig. Das Prototype-Framework basiert darauf, die Prototypen von Objekten zu verändern; jQuery hingegen erzeugt Objekte eines eigenen Typs, anstatt den gesamten JavaScript-Kosmos zu manipulieren. Die jQuery-Basisfunktion (also "$()") nimmt jedoch auch beliebige DOM-Nodes entgegen und liefert sie als jQuery-Objekt zurück, d.h. aus Deinem "formObj.elements[e].irgendwas()" kannst Du einfach "$(formObj.elements[e]).jQueryAequivalent()" machen.

        Mein Versuch, die erste Anweisung im Schleifenblock zu erstzen:
        $(':input:not(:hidden)').each(function(){eA[this.name]=this;});
        ... scheitert aber. Der Selektor scheint korrekt zu sein.

        Du hast hiernach, genau wie bisher, die DOM-Nodes in Deinem Array. jQuery-Objekte machst Du daraus wie oben beschrieben.

        Jetzt frage ich mich, ob es grundsätzlich ein Fehler ist,
        das Array 'eA' zu definieren um mit mehreren Funktioneen
        darauf zuzugreifen, weil global evil ist,

        Der globale Scope sollte möglichst sauber gehalten werden, das stimmt. Du kannst Dein Array als Eigenschaft eines günstig gewählten Objektes abspeichern, wenn Du magst; für den Anfang kannst Du window dieses Objekt sein lassen.

        oder ich nur wissen muss, wie ich hier:
        $(':input:not(:hidden)').each(function(){eA[this.name]=this;});
        ... dafür sorge, dass jQuery weiss, dass ich das global definierte
        Array 'eA' füllen möchte.

        jQuery erfährt nicht mal, dass Du da ein Array füllen willst. Das ist handelsübliches JavaScript.

        Cheatah

        --
        X-Self-Code: sh:( fo:} ch:~ rl:| br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
        X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
        X-Will-Answer-Email: No
        X-Please-Search-Archive-First: Absolutely Yes
        1. hi,

          oder ich nur wissen muss, wie ich hier:
          $(':input:not(:hidden)').each(function(){eA[this.name]=this;});
          ... dafür sorge, dass jQuery weiss, dass ich das global definierte
          Array 'eA' füllen möchte.

          jQuery erfährt nicht mal, dass Du da ein Array füllen willst. Das ist handelsübliches JavaScript.

          Nachdem mir nun klar ist, wann in JS Variablen global und wann
          lokal definiert sind (Schande.Warum eigentlich erst jetzt?)
          habe ich meine Variablen mal aufgeräumt und dachte, dann müsse
          das ja auch funktionieren. Tat es nicht. Konnte aber nicht sein.
          Jetzt hab ich's gefunden:

          $(':input:not(:hidden)').each(function(){eA[this.name]=this;});

          ... belegt tatsächlich wie erwartet das Array 'eA' als
          assoziatives Array mit den DOM-Objekten alá:

          eA['title'] = Object HtmlInput

          Dass es nicht beim ersten Versuch funktionierte, lag aber nicht
          an unsauber deklarierten Variablen, sondern daran, dass mein
          Input name="title" zwar vom Typ="text" war, aber per css mit
          display:none versteckt wird und aufgrund dessen nicht von
          $(':input:not(:hidden)') erfasst wurde, weil "not(:hidden)"
          sich garnicht auf type="hidden", sondern auf alles, was nicht
          angezeigt wird bezieht ;)

          gruesse,
          heinetz

          1. Mahlzeit heinetz,

            $(':input:not(:hidden)').each(function(){eA[this.name]=this;});

            Was genau soll eigentlich der Doppelpunkt vor dem "input"?

            MfG,
            EKKi

            --
            sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
            1. hallo ekki,

              Was genau soll eigentlich der Doppelpunkt vor dem "input"?

              der meint nicht nur input sondern auch textarea usw. wie hier
              beschrieben.

              Ich bin allerdings gerade über meinen (glaube ich) nächsten
              grundsätzlichen Denkfehler gefallen. So sah mein funktionierender
              Code mal aus:

              formObj = document.forms['adminForm'];  
              for (var i=0; i<formObj.elements.length; i++)  
                 {  
                  if(formObj.elements[i].type!="hidden") eA[formObj.elements[i].name] = formObj.elements[i];  
                  formObj.elements[i].onfocus = function (){lA[this.name].className = "";}  
                 }  
              eA['site_id'] = formObj.elements['site_id'];
              

              Damit hatte ich zum Einen einen Event für alle elements in
              meinem Form definiert und, was für meine Logik wesentlicher
              war, alle elements, die nicht vom type="hidden" waren in
              mein Array eA geschrieben. Und zusätzlich das element mit
              dem namen 'site_id', was eben doch vom type="hidden" war.

              Mit JQuery habe ich das ganze so versucht:

              $(':input').focus(function(){lA[this.name].className = "";});  
              $(":input:not(input[type='hidden'])").each(function(){eA[this.name]=this;});  
              eA['site_id'] = $("input[name='site_id']");
              

              ... und mit der letzten Zeile konnte nicht das gewünschte
              bewirken. Ich glaube, ich habe verstanden warum:

              Ich schreibe nicht das DOM-Objekt in mein Array, sondern
              das JQuery-Objekt!

              Die Lösung liegt sicher darin, den Selektor noch weiter
              zu verfeinern:

              1. Alle :input
              2. ausser type=hidden
              3. wenn nicht name=site_id

              Was dann noch fehlt ist die Verfeinerung:

              1. Alle :input im form name="adminForm"

              beste gruesse,
              heinetz

              1. hi,

                Die Lösung liegt sicher darin, den Selektor noch weiter
                zu verfeinern:

                1. Alle :input
                2. ausser type=hidden
                3. wenn nicht name=site_id

                Was dann noch fehlt ist die Verfeinerung:

                1. Alle :input im form name="adminForm"

                ich habe etwas gefunden, was zu gehen scheint:

                $("form[name='adminForm'] :input:not(input[type='hidden']), input[name='site_id']")

                ... spricht:

                1. alle INPUT, TEXTAREA usw.
                2. in dem FORM name="adminForm"
                3. ausser sie sind vom type="hidden"
                4. und das INPUT mit name="site_id" an

                Ich habe allerdings erst folgendes versucht:

                $("form[name='adminForm'] :input:not(input[type='hidden']),form[name='adminForm'] input[name='site_id']")

                Das erschien mir logischer, weil die Notation CSS-Syntax eher
                entspricht, führt aber zum Fehler.

                Gilt der Parent vor dem Komma nun tatsächlich auch für den
                Teil hinter dem Komma oder ist in dem Teil nach dem Komma
                nun garkein parent für mein INPUT definiert ?

                danke für Tipps und

                beste gruesse,
                heinetz

        2. ... steckt, ist dass ich versucht habe, ein JQ-Methode auf ein
          DOM-Objekt anzuwenden.

          richtig. Das Prototype-Framework basiert darauf, die Prototypen von Objekten zu verändern; jQuery hingegen erzeugt Objekte eines eigenen Typs, anstatt den gesamten JavaScript-Kosmos zu manipulieren.

          Das kann man so nicht sagen. Auch bei Prototype kann man nicht ohne weiteres Methoden der Bibliothek auf Elementobjekten aufrufen. Sie müssen vorher manuell durch $() bzw. $$() erweitert werden. Das ist also keine prototypische Erweiterung, sondern vielmehr ein Mixin. Prototype erweitert ECMAScript-Kernobjekte prototypisch, aber nicht DOM-Objekte. Das geht nämlich erst in neueren Browsern, deshalb ist für Elementobjekte das manuelle Erweitern nötig.

          jQuery setzt m.E. ein Facade-Pattern um, welches einzelne DOM-Elementknoten zu Elementlisten kapselt. Andere nennen es in Anlehnung an Haskell Monade.

          Disclaimer: IANA computer scientist.

          Mathias

  2. jedes input type="text"

    input:focus{

    }

      
    Das ist natürlich unsinn ;)  
      
    input[type=text]:focus wäre vermutlich wohl der Selektor der Wahl.