snoot: Div ausblenden, wenn man außerhalb klickt

Hi,

ich habe ein Eingabefeld und ein Div. Im Div stehen Links, deren ID bei onclick in das Eingabefeld übergeben werden soll. Das Div soll ausgeblendet werden, wenn man

a) einen Link anklickt, oder
  b) neben das Div klickt

Das mit dem Link klappt soweit einwandfrei:

<script type="text/javascript">  
  function insert_eingabe(id, div_id, txt_id)  
  {  
    var div = document.getElementById(div_id)  
    var txt = document.getElementById(txt_id)  
    if(txt && div)  
    {  
      txt.value = id;  
      div.style.visibility = 'hidden';  
    }  
  }  
</script>
<input type="text" id="eingabe">  
<div id="div">  
  <a id="1" href="#" onclick="insert_eingabe(id, 'div', 'eingabe')">Link 1</a><br>  
  <a id="2" href="#" onclick="insert_eingabe(id, 'div', 'eingabe')">Link 2</a><br>  
  <a id="3" href="#" onclick="insert_eingabe(id, 'div', 'eingabe')">Link 3</a><br>  
</div>

Aber wie frage ich das "Danebenklicken" ab?

Ich dachte ich mache das, sobald das Eingabefeld den Focus verliert (es hat den Focus vorher, bei sichtbarem Div, *immer*):

<script type="text/javascript">  
  function schliessen(div_id)  
  {  
    var div_id = document.getElementById(div_id);  
    div_id.style.visibility = 'hidden';  
  }  
</script>
<input type="text" id="eingabe" onblur="schliessen('div')">  
<div id="div">  
  <a id="1" href="#" onclick="insert_eingabe(id, 'div', 'eingabe')">Link 1</a><br>  
  <a id="2" href="#" onclick="insert_eingabe(id, 'div', 'eingabe')">Link 2</a><br>  
  <a id="3" href="#" onclick="insert_eingabe(id, 'div', 'eingabe')">Link 3</a><br>  
</div>

Dummerweise ist das "onblur" schneller als das "onclick", d.h. das Div ist weg, bevor der angeklickte Link registriert wird. Es wird beim Klick also das Div geschlossen und die ID nicht mehr übergeben.

Wie könnte ich sonst noch feststellen, ob irgendwo außerhalb des Divs geklickt wird?

  1. Hi,

    Aber wie frage ich das "Danebenklicken" ab?

    Du musst zum Zuklappen den Klick im document registrieren, aber verhindern, dass der Klick auch dann im document aufläuft, wenn Du auf die Liste klickst. Dafür gibts cancleBubble (IE's) resp. stopPropagation, Methoden, die das "Hochblubbern" des events in der Dom-Hirarchie verhindern. Schau Dir mal diesen Test an, könnte Dir weiterhelfen: http://www.wendenburg.de/test/listitem_to_input.html

    Ist jetzt allerdings nur schnell am FF/Mac gestrickt, hab leider keine Zeit allles durchzutesten. Verbesserungen willkommen...

    Gruesse, Joachim

    --
    Am Ende wird alles gut.
    1. Du musst zum Zuklappen den Klick im document registrieren, aber verhindern, dass der Klick auch dann im document aufläuft, wenn Du auf die Liste klickst. Dafür gibts cancleBubble (IE's) resp. stopPropagation, Methoden, die das "Hochblubbern" des events in der Dom-Hirarchie verhindern. Schau Dir mal diesen Test an, könnte Dir weiterhelfen: http://www.wendenburg.de/test/listitem_to_input.html

      Ist jetzt allerdings nur schnell am FF/Mac gestrickt, hab leider keine Zeit allles durchzutesten. Verbesserungen willkommen...

      Gruesse, Joachim

      Danke, hab jetzt noch was kürzeres gefunden:

      document.onclick = function(e)  
      {  
        if(!e)  
        {  
          e = window.event;  
        }  
        var obj = e.target ? e.target : e.srcElement ? e.srcElement : null;  
        if( div_id != obj )  
        {  
          div_id.style.display = 'none';  
        }
      

      Scheint eigentlich in allen Browsern (IE/FF/Opera/Chrome/Safari) zu laufen.

      1. document.onclick = function(e)

        {
          if(!e)
          {
            e = window.event;
          }
          var obj = e.target ? e.target : e.srcElement ? e.srcElement : null;
          if( div_id != obj )
          {
            div_id.style.display = 'none';
          }

        
        >   
        > Scheint eigentlich in allen Browsern (IE/FF/Opera/Chrome/Safari) zu laufen.  
          
        Das kann nicht sein.  
          
        Du fragst hier ab, welches Element das Ziel des Klicks ist - und vergleichst, ob dieses Element identisch mit dem div-Container ist.  
          
        Wenn ich allerdings auf einen Link im div-Element klicke, so ist der Link das Ziel des Events. D.h. div != Event-Target, also müsste das div versteckt werden. Das war aber nicht Sinn der Sache, oder?  
          
        Der Ansatz ist aber schon ganz richtig, aber dich interessiert vielmehr, ob das Zielelement  
        1\. das div selbst ist  
        2\. oder ein Element, das im div liegt (halt ein Link)  
          
        Dazu bieten die Browser außer Firefox die Methode .contains() an:  
          
        if (eventTarget != divContainer && !divContainer.contains(eventTarget)) {  
           /\* Klick kam nicht vom div oder seinen Kindelementen \*/  
        }  
          
        Für den Firefox bindest du [dieses Script](http://forum.de.selfhtml.org/archiv/2008/7/t173611/#m1140229) ein, sodass er ebenfalls .contains() kennt.  
          
        Mathias
        
        -- 
        [JavaScript-Erweiterung für das SELFHTML-Forum](http://forum.de.selfhtml.org/js/doku/)
        
        1. Du fragst hier ab, welches Element das Ziel des Klicks ist - und vergleichst, ob dieses Element identisch mit dem div-Container ist.

          Wenn ich allerdings auf einen Link im div-Element klicke, so ist der Link das Ziel des Events. D.h. div != Event-Target, also müsste das div versteckt werden. Das war aber nicht Sinn der Sache, oder?

          Eigentlich schon, ich wollte ja:

          div verschwindet bei

          a) Klick auf Link, oder
            b) Klick neben div

          Also macht die Funktion im Grunde alles richtig - wenn auch unbeabsichtigt. Beim Klick auf einen Link würde das div auch verschwinden, weil das dann die onclick-Funktion erledigt.

          1. Also macht die Funktion im Grunde alles richtig - wenn auch unbeabsichtigt. Beim Klick auf einen Link würde das div auch verschwinden, weil das dann die onclick-Funktion erledigt.

            Okay. Aber dann verstehe ich ehrlich gesagt den Nutzen nicht so recht.
            Bei einem Klick auf das div soll das Feld nicht verschwinden, ansonsten schon. Gut. Aber wieso sollte man auch auf das div klicken? Doch wohl eher aus Zufall? Es wird ja nicht suggeriert, dass da irgendeine Funktionalität hinter läge.

            Mathias

            1. Aber wieso sollte man auch auf das div klicken? Doch wohl eher aus Zufall? Es wird ja nicht suggeriert, dass da irgendeine Funktionalität hinter läge.

              Mathias

              Doch:

              Im Div stehen Links, deren ID bei onclick in das Eingabefeld übergeben werden soll

              Das div soll im Grunde immer verschwinden (bei einem Klick *ins* div aber erst nachdem die Link-ID übergeben wurde; daher ging mein erster Ansatz mit onblur nicht).

              Hier mal die Seite. Bei Texteingabe in einem der beiden Suchfelder erscheint ein div mit Links. Bei Klick auf einen Link oder neben das div, soll sich selbiges wieder schließen.

              1. Im Div stehen Links, deren ID bei onclick in das Eingabefeld übergeben werden soll

                Das ist mir schon klar.

                Hier mal die Seite. Bei Texteingabe in einem der beiden Suchfelder erscheint ein div mit Links. Bei Klick auf einen Link oder neben das div, soll sich selbiges wieder schließen.

                Wie gesagt: Das div hat selbst keine Fläche, die nicht von einem Kindelement, insbesondere von den Links eingenommen wird.
                Daher ist die Abfrage, ob nicht das div selbst geklickt wurde (nicht deren Kindelemente!), also letztliches Zielelement des Events ist, ziemlich überflüssig - soweit ich das richtig verstehe.

                Mathias

                1. Damit wir uns richtig verstehen: Was wäre daran problematisch?

                  document.onclick = function () {
                     document.getElementById("suggest").style.display = 'none';
                  };

                  Wenn das div selbst keine eigene Fläche hat, die nicht von einem Kindelement und vor allem den Links eingenommen wird, kann die Abfrage doch wegfallen?

                  Mathias

                  1. Damit wir uns richtig verstehen: Was wäre daran problematisch?

                    document.onclick = function () {
                       document.getElementById("suggest").style.display = 'none';
                    };

                    Wenn das div selbst keine eigene Fläche hat, die nicht von einem Kindelement und vor allem den Links eingenommen wird, kann die Abfrage doch wegfallen?

                    Ja, es sieht in der Tat so aus. Da hab ich eben viel zu kompliziert gedacht. Das kommt davon, wenn man wenig Ahnung von der Materie hat ;)

                    Da kann ich nur sagen, herzlichen Dank für die tatkräftige Unterstützung.

    2. http://www.wendenburg.de/test/listitem_to_input.html

      Wenn man ohnehin mit Event Delegation arbeitet, kann man auch die Klicks auf oberster Ebene filtern, anstatt das Bubbling auf unterster Ebene bei jedem li-Elemente einzeln herauszufiltern.

      Überhaupt leuchtet mir gerade nicht ein, wieso jedes li den cancel_bubble-Handler braucht.

      linklist_wrapper.onclick        =   cancel_bubble;

      ... sollte doch schon alle Event stoppen, die vom linklist-Wrapper *oder* seinen Kindelementen aufsteigen.

      Mathias

      1. Hi,

        Wenn man ohnehin mit Event Delegation arbeitet, kann man auch die Klicks auf oberster Ebene filtern.

        Auf jeden Fall. Das ist ein C&P-Überbleibsel, Sorry. In Zeile 78 steht ja schon:
        linklist_wrapper.onclick        =   cancel_bubble;

        Gruesse, Joachim

        --
        Am Ende wird alles gut.