bobby: Javascript Functionen = KRIEGSFUSS

Moin,

arrrgh... ich verzweifel hier langsam. Ich habe ein Bild, und möchte gern die originale Größe des Bildes haben (aus der Datei).

dazu habe ich mir eine kleine Funktion geschrieben. Wie bekomme ich den Wert außerhalb der Funktion?

 function checkSize(image) {
        img = new Image();
        img.src = image.attr('src');
        img.onload = function() {
            console.info(this.width);
        };
    }

checkSize($('img#einBild'));

wie bekomm ich dieses "this.width" außerhalb der Funktion gebracht. ich will es später wieder verwenden.

Gruß Bobby

--
-> Für jedes Problem gibt es eine Lösung, die einfach, sauber und falsch ist! <- ### Henry L. Mencken ### -> Nicht das Problem macht die Schwierigkeiten, sondern unsere Sichtweise! <- ### Viktor Frankl ### ie:{ br:> fl:{ va:} ls:< fo:) rl:( n4:( de:> ss:) ch:? js:( mo:} sh:) zu:)

akzeptierte Antworten

  1. Hallo

     function checkSize(image) {
            img = new Image();
            img.src = image.attr('src');
            img.onload = function() {
                console.info(this.width);
            };
        }
    
    checkSize($('img#einBild'));
    

    wie bekomm ich dieses "this.width" außerhalb der Funktion gebracht. ich will es später wieder verwenden.

    Mit return this.width; und Übergabe des Rückgabewertes an eine Variable var imageWidth = checkSize($('img#einBild')); sollte das gehen.

    Tschö, Auge

    --
    Es schimmerte ein Licht am Ende des Tunnels und es stammte von einem Flammenwerfer.
    Terry Pratchett, „Gevatter Tod“
  2. Hallo,

    Deine Funktion soll also etwas zurückgeben.

    Gruß
    Kalk

    1. Moin,

      Deine Funktion soll also etwas zurückgeben.

      Funktioneirt Asynchgron nicht. Damit habe ich jetzt bis zur genüge rum experimentiert

      Gruß Bobby

      --
      -> Für jedes Problem gibt es eine Lösung, die einfach, sauber und falsch ist! <- ### Henry L. Mencken ### -> Nicht das Problem macht die Schwierigkeiten, sondern unsere Sichtweise! <- ### Viktor Frankl ### ie:{ br:> fl:{ va:} ls:< fo:) rl:( n4:( de:> ss:) ch:? js:( mo:} sh:) zu:)
  3. Tach!

     function checkSize(image) {
            img = new Image();
            img.src = image.attr('src');
            img.onload = function() {
                console.info(this.width);
            };
        }
    
    checkSize($('img#einBild'));
    

    wie bekomm ich dieses "this.width" außerhalb der Funktion gebracht. ich will es später wieder verwenden.

    (Er)klär bitte erstmal, worauf this zeigt. Im gezeigten Code kann ich nicht erkennen, dass es überhaupt eine Eigenschaft width hat, und die kann man es auch ganz schwer "nach außen bringen".

    dedlfix.

    1. Tach!

       function checkSize(image) {
              img = new Image();
              img.src = image.attr('src');
              img.onload = function() {
                  console.info(this.width);
              };
          }
      
      checkSize($('img#einBild'));
      

      wie bekomm ich dieses "this.width" außerhalb der Funktion gebracht. ich will es später wieder verwenden.

      (Er)klär bitte erstmal, worauf this zeigt. Na in dem Eventhandler wohl ziemlich sicher auf "img"?!

      1. Tach!

         function checkSize(image) {
                img = new Image();
                img.src = image.attr('src');
                img.onload = function() {
                    console.info(this.width);
                };
            }
        
        checkSize($('img#einBild'));
        

        wie bekomm ich dieses "this.width" außerhalb der Funktion gebracht. ich will es später wieder verwenden.

        Arg, i hate kramdown....

        Na in dem Eventhandler wohl ziemlich sicher auf "img"?!

        1. Hallo Mitleser,

          Arg, i hate kramdown....

          Was hat das versehentliche Absenden eines Beitrags mit Kramdown zu tun?

          Bis demnächst
          Matthias

          --
          Signaturen sind bloed (Steel) und Markdown ist mächtig.
        2. Tach!

          Na in dem Eventhandler wohl ziemlich sicher auf "img"?!

          Stimmt, da war noch eine Funktion als Eventhandler, die ich übersehen habe.

          In dem Fall muss man da ganz anders vorgehen. Die zeitgemäße Lösung bei solchen asynchronen Sachen lautet Promise. Man kann zunächst mal gar kein Ergebnis zurückliefern, weil erst irgendwann nach dem Ende der umschließenden Funktion das Event auftritt. Hier hilft nun ein Promise, welches man erst einmal zurückgibt. Dieses Versprechen wird später eingelöst oder vielleicht doch abgewiesen.

          Promises gibt es erst mit ES6 direkt in Javascript, wenn man Kompatibilität mit noch nicht unterstützenden Browsern brauchst, kannst man einen Nachbau nehmen, beispielsweise Q.

          dedlfix.

  4. dazu habe ich mir eine kleine Funktion geschrieben. Wie bekomme ich den Wert außerhalb der Funktion?

     function checkSize(image) {
            img = new Image();
            img.src = image.attr('src');
            img.onload = function() {
                console.info(this.width);
            };
        }
    
    checkSize($('img#einBild'));
    

    wie bekomm ich dieses "this.width" außerhalb der Funktion gebracht. ich will es später wieder verwenden.

    Da Du hier asynchron arbeitest, kannst Du hier nicht mit einem klassichen "return" arbeiten. Wenn das "onload" eintritt, ist es dafür zu spät. Eine Alternative: übergib checkSize als zweiten Parameter eine Callback-Funktion, die Du dann mit den Werte aus dem "onload" aufrufst. Außerdem setz den Event-Handler besser vor der Änderung des SRC-Attributs. Es ist nicht ausgeschlossen, dass der Browser-Cache sonst schneller ist.

    1. Moin,

      Da Du hier asynchron arbeitest, kannst Du hier nicht mit einem klassichen "return" arbeiten.

      GENAU das ist mein Problem. Ich kommentiere die ersten Antworten aber nicht weiter.

      Wenn das "onload" eintritt, ist es dafür zu spät. Eine Alternative: übergib checkSize als zweiten Parameter eine Callback-Funktion, die Du dann mit den Werte aus dem "onload" aufrufst.

      ??? Kannst du mal kurz ansetzen?

      Außerdem setz den Event-Handler besser vor der Änderung des SRC-Attributs. Es ist nicht ausgeschlossen, dass der Browser-Cache sonst schneller ist.

      OK, danke für diesen Hinweis.

      Gruß Bobby

      --
      -> Für jedes Problem gibt es eine Lösung, die einfach, sauber und falsch ist! <- ### Henry L. Mencken ### -> Nicht das Problem macht die Schwierigkeiten, sondern unsere Sichtweise! <- ### Viktor Frankl ### ie:{ br:> fl:{ va:} ls:< fo:) rl:( n4:( de:> ss:) ch:? js:( mo:} sh:) zu:)
  5. Moin,

     function checkSize(image) {
            img = new Image();
            img.src = image.attr('src');
            img.onload = function() {
                console.info(this.width);
            };
        }
    
    checkSize($('img#einBild'));
    

    habs jetzt anders gelöst:

    function checkSize(image) {
            var img = new Image();
            img.onload = function() {
                console.info(this.width);
            };
            img.src = image.attr('src');
            return img.width;
        }
    
    var width=checkSize($('img#einBild'));
    

    Das scheint zu funktionieren. Irgendwelche Bedenken?

    EDIT: Doch nicht. :( Beim ersten Aufruf ist die Breite 0 ... Bedingt durch den Cache gab es die richtige Ausgabe. :(

    Gruß Bobby

    --
    -> Für jedes Problem gibt es eine Lösung, die einfach, sauber und falsch ist! <- ### Henry L. Mencken ### -> Nicht das Problem macht die Schwierigkeiten, sondern unsere Sichtweise! <- ### Viktor Frankl ### ie:{ br:> fl:{ va:} ls:< fo:) rl:( n4:( de:> ss:) ch:? js:( mo:} sh:) zu:)
    1. Tach!

      function checkSize(image) {
              var img = new Image();
              img.onload = function() {
                  console.info(this.width);
              };
              img.src = image.attr('src');
              return img.width;
          }
      
      var width=checkSize($('img#einBild'));
      

      Das scheint zu funktionieren. Irgendwelche Bedenken?

      EDIT: Doch nicht. :( Beim ersten Aufruf ist die Breite 0 ... Bedingt durch den Cache gab es die richtige Ausgabe. :(

      Es ist immer noch das alte Zeit-Problem. Die Anweisung img.src = ... wartet nicht. Die nächste Anweisung wird sofort ausgeführt, und da ist das Laden aber noch nicht fertig.

      Du musst diese zeitlichen Abhängigkeiten unbedingt verstehen und berücksichtigen, sonst wird das nie was werden mit den asynchronen Abläufen. Und die kannst du auch nicht wegignorieren.

      Es gibt zwei generelle Wege. Der eine ist, du lässt dir eine Callback-Funktion übergeben, die du dann aufrufst, wenn das Ereignis stattfand. Aber auch hier musst du bachten, dass diese Funktion erst später aufgerufen wird, und alles was auf das Ergebnis angewiesen ist, auch erst zu diesem Später-Zeitpunkt laufen darf.

      Der zweite Weg hört auf den Namen Promise. Das ist ein generelles Lösungsmuster für dieses Problem mit der Asynchronität.

      Vielleicht hast du schon einmal Ajax mit jQuery gemacht, da gibt es beide Wege. Der erste ist Callback-Übergabe und ist recht bekannt. Neuerdings kann man aber auch das Promise-Muster verwenden.

      Ohne Anspruch auf syntaktische Richtigkeit zunächst mal die Callback-Methode:

      $ajax({
        data: parameter,
        success: function (...) { /* callback bei Erfolg */ },
        error: function (...) { /* callback bei Fehler */ }
      });
      

      Von der Promise-Methode sieht man nur einen Teil:

      $ajax({
        data: parameter
      })
      .done(function () { /* callback bei Erfolg */ })
      .fail(function () { /* callback bei Fehler */ });
      

      Das ist der Teil der Verwendung. Du brauchst noch den anderen Teil, das Erzeugen des Promises und die Erfüllung beziehungsweise Zurückweisung im Fehlerfall. Ich verweise statt langer Erklärung erstmal auf das Promise-Beispiel im MDN.

      dedlfix.

    2. Hallo,

      wie schon beschrieben, wegen der Asyncronität benötigst du eine Callback-Funktion, die vom Eventhandler aufgerufen wird.

      // Nicht getestet! Tippfehler möglich.
      function checkSize(image, callbackfunktion) {
              var img = new Image();
              img.onload = function() {
                  console.info(this.width);
                  callbackfunktion(this.width);
              };
              img.src = image.attr('src');
          }
      
      function tu_was(w) {
      // mach irgendetwas mit der Breite
      }
      
      checksize($('img#einBild', tu_was);
      

      Gruß Jürgen

      1. Moin,

        wie schon beschrieben, wegen der Asyncronität benötigst du eine Callback-Funktion, die vom Eventhandler aufgerufen wird.

        Ich hatte nach nem Beispiel gerufen, und hier ist es. DANKE. So funktioniert es tatsächlich.

        Gruß Bobby

        --
        -> Für jedes Problem gibt es eine Lösung, die einfach, sauber und falsch ist! <- ### Henry L. Mencken ### -> Nicht das Problem macht die Schwierigkeiten, sondern unsere Sichtweise! <- ### Viktor Frankl ### ie:{ br:> fl:{ va:} ls:< fo:) rl:( n4:( de:> ss:) ch:? js:( mo:} sh:) zu:)
  6.  function checkSize(image) {
            img = new Image();
            img.src = image.attr('src');
            img.onload = function() {
                console.info(this.width);
            };
        }
    
    checkSize($('img#einBild'));
    

    wie bekomm ich dieses "this.width" außerhalb der Funktion gebracht. ich will es später wieder verwenden.

    Als Erstes solltest du dir bewusst sein, dass .width erst zur Verfügung stehen wird, wenn das Bild geladen ist, wenn also das Ereignis onload ausgelöst bzw. abgearbeitet wurde. Ich erwähne das extra, weil du hier in einem zweiten Beitrag eine eigene Lösung beschrieben hast, die dann -onload und seinen zeitlichen Ablauf beachtend eigentlich wenig überraschend- doch nicht funktionierte.

    Insofern ist dein Ansatz hier etwas unvollständig, es fehlt der Teil, der "später" .width verarbeiten soll. Andererseits hast du ihn hier in gewisser Hinsicht schon drin – in Form von console.info(this.width). Ersetze diese Zeile mit allem, was nach checkSize($('img#einBild')); kommt und sich auf .width bezieht.

    Falls die Breite auf verschiedene Arten verarbeitet werden soll, müsstest du stattdessen je nach Situation checkSize() eine Funktion übergeben, die diese Verarbeitung übernimmt:

    function machWasMitBreite(image, funktion) {
           img = new Image();
           img.src = image.attr('src');
           img.onload = funktion;
    }
     
    machWasMitBreite($('img#einBild'), function () {
       console.info("mache dies mit " + this.width);
       var b = this.width;
       rhabarber(b * 2);
    });
    
    machWasMitBreite($('img#irgendeinAnderesBildInEinemAnderenZusammenhang'), function () {
       console.info("mache irgendwas anderes mit " + this.width);
       var bla = fasel(this.width) / 5;
    });
    
  7.  function checkSize(image) {
            img = new Image();
            img.src = image.attr('src');
            img.onload = function() {
                console.info(this.width);
            };
        }
    
    checkSize($('img#einBild'));
    

    Es ist hier nicht nötig auf eigene Faust mit DOM-Objekten zu jonglieren. jQuerys Pendant zur onload-Eigenschaft ist die load-Methode:

    $('img#einBild').load(function(loadEvent){
       $image = $(loadEvent.target);
       console.log($image.width());
    });
    
    1. Moin,

      Es ist hier nicht nötig auf eigene Faust mit DOM-Objekten zu jonglieren. jQuerys Pendant zur onload-Eigenschaft ist die load-Methode:

      $('img#einBild').load(function(loadEvent){
         $image = $(loadEvent.target);
         console.log($image.width());
      });
      

      Danke. ist sogar bisschen schneller.

      Gruß Bobby

      --
      -> Für jedes Problem gibt es eine Lösung, die einfach, sauber und falsch ist! <- ### Henry L. Mencken ### -> Nicht das Problem macht die Schwierigkeiten, sondern unsere Sichtweise! <- ### Viktor Frankl ### ie:{ br:> fl:{ va:} ls:< fo:) rl:( n4:( de:> ss:) ch:? js:( mo:} sh:) zu:)