2011-01-03 2 views
1

J'écris un plugin pour jQuery et j'ai un bordel dans la tête avec le problème de contexte en javascript.jQuery plugin, context et setTimeout

Ceci est une version simplifiée de mon plugin:

(function($){ 

$.fn.myplugin = function(options){ 
    return new MyPlugin(this, options); 
}; 


function MyPlugin(el, o) 
{ 
    this.root = el; 
    this.input_box = el.find('#the_input'); 
    this.map = null; 
    this.timeout = null; 
    var self = this; 

    self.input_box.keyup(function(){ 
    if(self.timeout!==null) 
    { 
     clearTimeout(self.timeout); 
    } 
    self.timeout = setTimeout(function(){ 
      self.search_address(self); 
      }, 500); 
    }); 
} 

MyPlugin.prototype = { 

    search_address : function(context){ 
      geocoder.geocode({'address':$('#direction').val()}, 
      function(results, status){ 
       var lat = results[0].geometry.location.lat(); 
       var lng = results[0].geometry.location.lng(); 
       var latlng = new google.maps.LatLng(lat, lng); 

       context.select_address(latlng, '');         
    }, 

    select_address : function(latlng, text){ 
     self.root.find('#url').val('http://maps.google.com/?q='+encodeURI($('#direccion').val())+'&ll='+coords.lat()+','+coords.lng()+'&ie=UTF8&oe=UTF8&z=18'); 
    } 
}; 
})(jQuery); 

J'ai lu que setTimeout définit le contexte de l'objet global, donc je l'ai fait la fermeture pour pouvoir passer le contexte de search_address fonction. Cela m'a permis d'appeler select_address à partir de la fonction de rappel geocode, mais ce rappel appelle select_address et là encore le contexte est de nouveau indésirable: self.root est introuvable.

Je suis perdu à completly la façon de gérer le contexte, je pensais que l'utilisation du var self=this à l'initialisation du « objet » Je voudrais éviter ces problèmes ...

je dois noter que select_address peut être appelé directement ...

Répondre

1

Utilisez this à ce moment-là pour faire référence au contexte actuel:

select_address : function(latlng, text){ 
    this.root.find('#url').val('http://maps.google.com/?q='+encodeURI($('#direccion').val())+'&ll='+coords.lat()+','+coords.lng()+'&ie=UTF8&oe=UTF8&z=18'); 
} 
+0

pourquoi le moi ne fonctionne pas là-dedans? Gardez à l'esprit que select_address peut être appelé directement ... Je voudrais connaître une règle pour gérer cela et éviter les tâtonnements. –

+0

'self' est une variable que vous avez, mais elle n'est pas présente dans la portée actuelle. Si vous avez besoin du contexte actuel, vous pouvez utiliser 'this', vous utilisez juste un porteur de référence comme' self' quand 'this' peut changer, comme dans un callback que vous ne contrôlez pas. –

+0

Donc je devrais créer un "self" var dans n'importe quel endroit le contexte peut changer et ne peut pas compter sur l'auto créé dans l'initialiseur ... Donc c'est une bonne pratique d'avoir à passer un contexte aux callbacks? –

1

Je viens de découvrir quelque chose de cool qui fixe le contexte setTimeOut dans jQuery 1.4+.

Vous pouvez utiliser jQuery.proxy pour résoudre le problème de contexte.

Voici mon code:

 

    Application = function() 
    { 
     this.AMethod = function(){}; 

     setTimeout($.proxy(this.AMethod,this), 100); 


    } 

Après le délai d'attente, le Application.AMethod est exécuté et donc le contexte "Application" est maintenue

LE: Alternativelly vous pouvez créer votre propre fonction proxy très simplement si vous ne voulez pas que votre plugin se limite uniquement à jQuery 1.4+:

 

    function proxy(func, context) 
    { 
     return function(){ return func.apply(context, arguments);} 
    }