Linuchs: freies Hilfsfeld beim Tippen andocken, left und top finden

Moin,

bei Eingabe von Orten kommen Vorschläge per Ajax zum Anklicken.

Bisher hatte ich das Vorschlags-div HTML-mäßig an das input-Feld geklebt. Nun gibt es aber mehrere input-Felder in einer form und ich möchte die Vorschläge variabel positionieren.

Das Feld parke ich mit position:absolute;display:none erstmal oben links auf der Seite.

Wenn mehr als 2 Zeichen eingegeben werden, holt sich Ajax die Vorschläge vom Server und das „freie“ Vorschlagsfeld soll an das aktuelle input-Feld angedockt werden.

Irgendwie klappt's nicht mit der Positionierung, es erscheint viel zu weit unten auf der Seite.

Ausgehend vom aktuellen input-Feld (obj) hole ich mir left und top auf diese Weise:

/* *******************************************
 * Neues obj, Vorschlagsfeld positionieren
 * ******************************************* */
if ( obj.name != getOrteVar.obj.name ) {
  getOrteVar.obj = obj;        // speichern/merken fuer die UEbername Vorschlagswert
  var left = 5;                                   // 5px rechts vom Feldanfang ansetzen
  var top  = obj.offsetHeight +obj.clientHeight;  // unterhalb des Eingabefeldes ansetzen
  var obj2 = obj.parentElement;
  while ( obj2.tagName != "BODY" && obj2.style.position != "absolute" && obj2.style.position != "relative" ) {
    left  +=  obj2.offsetLeft;
    top   +=  obj2.offsetTop;
    obj2   =  obj2.parentElement;
  }
  getOrteVar.obj_vorschlaege.style.left  = left  +"px";
  getOrteVar.obj_vorschlaege.style.top   = top   +"px";
}

Weil ich nicht sicher bin, ob BODY standardmäßig absolut/relativ positioniert ist, habe ich body {position: relative;} definiert. Das Problem bleibt, auch wenn ich body klein schreibe.

Vielleicht sieht jemand den Haken sofort?

Gruß, Linuchs

  1. Hi there,

    Vielleicht sieht jemand den Haken sofort?

    Ich denke, Du addierst in der Schleife zu viele "tops" und "lefts" - warum fragst Du nicht einfach die Koordinaten vom Inputfeld ab, versetzt das Ganze um die Höhe des Inputfelds und gut ist's?

    1. Hallo klawischnigg

      warum fragst Du nicht einfach die Koordinaten vom Inputfeld ab?

      Wie geht das?

      Ich habe einen anderen Fall, da wird bei Mausklick etwas positioniert mit x/y des Mauszeigers.

      Aber hier wird z.B. mit der Tab-Taste ins Feld gesprungen und dann per Tastatur eingegeben. Das Feld ist als erstes Feld bei body eingehakt und benötigt die links-oben-Angaben von dort.

      Linuchs

      1. Hallo klawischnigg

        warum fragst Du nicht einfach die Koordinaten vom Inputfeld ab?

        Wie geht das?

        Mit der Funktion zum Beispiel:

        function getKoordinaten(obj) {
          let box = obj.getBoundingClientRect();
          return {
            top: box.top + pageYOffset,
            left: box.left + pageXOffset
          };
        }
        

        Ich habe einen anderen Fall, da wird bei Mausklick etwas positioniert mit x/y des Mauszeigers.

        Ja, da wird die Positionsbestimmung mit einer Event"abfrage" verknüpft. Hat aber im Prinzip mit der Positionsermittlung von Objekten nichts zu tun...

        1. Hallo klawischnigg,

          danke, das sieht unkompliziert aus.

          Habe es so umgesetzt:

          let box = obj.getBoundingClientRect();
          getOrteVar.obj_vorschlaege.style.left  = box.left + pageXOffset  +10 +"px";
          getOrteVar.obj_vorschlaege.style.top   = box.top + pageYOffset   +obj.offsetHeight +"px";
          

          Linuchs

    2. Hallo klawischnigg,

      ok, wie genau? getBoundingClientRect hängt am Viewport, d.h. wenn man scrollt, ändert sich der top-Wert.

      offsetTop hängt am offsetParent, d.h. es ist relativ zum nächstgelegenen positionierten Parent-Element.

      Irgendwie muss man die Elternkette ablaufen, aber wie genau, das ist so trivial nicht. Ich krieg's grad auch nicht hin.

      Update: jetzt erst dein Posting gelesen.

      Rolf

      --
      sumpsi - posui - obstruxi
  2. Hi,

    bei Eingabe von Orten kommen Vorschläge per Ajax zum Anklicken.

    Bisher hatte ich das Vorschlags-div HTML-mäßig an das input-Feld geklebt.

    Per datalist-Element ans jeweilige Input-Feld anbinden?

    cu,
    Andreas a/k/a MudGuard

    1. Hi there,

      bei Eingabe von Orten kommen Vorschläge per Ajax zum Anklicken.

      Bisher hatte ich das Vorschlags-div HTML-mäßig an das input-Feld geklebt.

      Per datalist-Element ans jeweilige Input-Feld anbinden?

      ja, das ist sicher die beste Lösung. Ich weiß nicht warum, aber ich vergeß' dieses Datalist-Element ständig...;)

    2. Moin Andreas,

      Per datalist-Element ans jeweilige Input-Feld anbinden?

      Sicher auch eine brauchbare Lösung.

      Die Klawischnigg-Lösung hat den Vorteil, dass ich im HTML den Input-Feldern, die durch den angeklickten Vorschag gefüllt werden sollen, nur den richtigen Namen verpassen muss:

      • ort_id
      • such_land_kz
      • such_plz
      • such_ort_name

      Alles andere macht getOrte.js. Beginnt damit, das Vorschlagsfeld bei body einzuhängen.

      Linuchs

      1. @@Linuchs

        Per datalist-Element ans jeweilige Input-Feld anbinden?

        Sicher auch eine brauchbare Lösung.

        Die Klawischnigg-Lösung hat den Vorteil …

        Ich bezweifle, dass du die brauchbar umgesetzt hast. Ist sie tastaturbedienbar?

        😷 LLAP

        --
        „Sag mir, wie Du Deine Maske trägst, und ich sage Dir, ob Du ein Idiot bist.“ —@Ann_Waeltin
  3. Weil ich nicht sicher bin, ob BODY standardmäßig absolut/relativ positioniert ist, habe ich body {position: relative;} definiert.

    In der zentralen CSS-Datei.

    Führt dazu, dass die Leaflet-Landkarte nur wenige Pixel hoch ist statt den ganzen Viewport zu füllen. Habe das wieder zurückgenommen.

    Im Inspektor der Landkarte kann man anklicken und den Effekt togglen:

    Stört nicht mehr, aber wäre wissenswert, warum.

    Linuchs

    1. Hallo Linuchs,

      ist doch klar.

      Die Map ist position:absolute, und du verwendest top, left, right und bottom, um ihre Grenzen festzulegen.

      Der Bezugspunkt für diese Werte wird entlang der Elternhierarchie gesucht, er ist das erste positionierte Element (d.h. alles außer dem Defaultwert position:static).

      Dein Body hat eine Höhe von 18px. Vermutlich wegen des einsamen   darin, das nicht aus dem Flow hinauspositioniert oder versteckt wird.

      Ohne position:relative am body orientiert sich die Map am Viewport.

      Lösung:

      body { 
         height: calc(100vh - 1em);
      }
      

      Minus ein emm wegen des Margins am Body. Sonst ist der Body zu hoch und es gibt rechts einen Scrollbar.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. @@Rolf B

        Lösung:

        body { 
           height: calc(100vh - 1em);
        }
        

        Minus ein emm wegen des Margins am Body. Sonst ist der Body zu hoch und es gibt rechts einen Scrollbar.

        Das ist wohl eher ein Hack als eine Lösung.

        Der Hack basiert darauf, das body { margin: 8px } im browserinternen Stylesheet steht und dass 1em 16px entspricht. Das kann gutgehen, muss aber nicht.

        Sauberer ist da

        body {
          margin: 0;
          min-height: 100vh;
        }
        

        und anderweitig dafür sorgen, dass der Inhalt nicht am Rand klebt.

        😷 LLAP

        --
        „Sag mir, wie Du Deine Maske trägst, und ich sage Dir, ob Du ein Idiot bist.“ —@Ann_Waeltin
        1. Hallo Gunnar,

          nein, das ist kein Hack. Es ist nur unvollständig beschrieben.

          Linuchs hat body { margin: 0.5em; } in seinem Stylesheet stehen. Ich habe unterstellt, dass ein alter Fux wie Linuchs den Zusammenhang zwischen Subtrahend und Margin erkennt, aber natürlich sieht das niemand, der die Seite nicht anschaut.

          Rolf

          --
          sumpsi - posui - obstruxi
          1. @@Rolf B

            Linuchs hat body { margin: 0.5em; } in seinem Stylesheet stehen. Ich habe unterstellt, dass ein alter Fux wie Linuchs den Zusammenhang zwischen Subtrahend und Margin erkennt, aber natürlich sieht das niemand, der die Seite nicht anschaut.

            Und auch nicht unbedingt jemand, der sich das Stylesheet anschaut. Das ist schlechter Code.

            Entweder

            body {
              --margin: 0.5em;
              margin: var(--margin);
              min-height: calc(100vh - 2 * var(--margin));
            }
            

            oder mit Präprozessor

            body {
              $margin: 0.5em;
              margin: $margin;
              min-height: calc(100vh - #{2 * $margin});
            }
            

            oder wenigstens in einem Kommentar vermerken, wo das 1em herkommt, welche Stellen also voneinander abhängen und bei Änderungen gemeinsam berücksichtigt werden müssen.

            😷 LLAP

            --
            „Sag mir, wie Du Deine Maske trägst, und ich sage Dir, ob Du ein Idiot bist.“ —@Ann_Waeltin
            1. @@Gunnar Bittersmann

              Entweder […]
              oder mit Präprozessor […]
              oder wenigstens in einem Kommentar […]

              oder

              html {
              	min-height: 100vh;
              	display: flex;
              }
              
              body {
              	flex: 1;
              	margin: 0.5em;
              }
              

              oder eine Zeile kürzer

              html {
              	min-height: 100vh;
              	display: grid;
              }
              
              body {
              	margin: 0.5em;
              }
              

              Look Ma, kein calc(), keine Abhängigkeiten.

              😷 LLAP

              --
              „Sag mir, wie Du Deine Maske trägst, und ich sage Dir, ob Du ein Idiot bist.“ —@Ann_Waeltin