Utilisation de this dans la fonction setInterval dans une classe

Signaler
Messages postés
10
Date d'inscription
jeudi 15 février 2007
Statut
Membre
Dernière intervention
18 mars 2010
-
Messages postés
3426
Date d'inscription
lundi 26 décembre 2005
Statut
Membre
Dernière intervention
14 janvier 2011
-
Bonjour,

Je rencontre un problème avec l'utilisation de this dans la fonction setInterval dans une classe.
Je reprends mon exemple (cf. http://www.javascriptfr.com/infomsg_DIAPORAMA-JAVASCRIPT_860013.aspx#6 ) :

function Diaporama(iInterval)
{
 this.iInterval = iInterval;
 this.oTimer = "";

 this.changeImage = function()
 {
    ...
  }

 this.startDiaporama = function()
 {
  var oThis = this;
  this.oTimer = window.setInterval(oThis.changeImage(), this.iInterval); 
 }

}

L'interpréteur Javascript tombe en erreur sur la commande setInterval après avoir exécuté 1 fois la commande << oThis.changeImage()
>>

J'ai essayé également ceci mais sans plus de succès :
window.setInterval(oThis.changeImage(), 1000); 

10 réponses

Messages postés
3426
Date d'inscription
lundi 26 décembre 2005
Statut
Membre
Dernière intervention
14 janvier 2011
14
B
onjour...

Ton problème n'est donc pas tout à fait le même 1000 excuses...
...d'une manière générale je pense qu'il est préférable de procéder comme suit.

//-- Création d'une fonction dans la zone globale
function Get_Fct_Change( o_){
  return( function(){o_.changeImage()});
// return l'adresse de la fonction
}

ensuite on fait l'appel de la façon suivante
  this.oTimer = setTimeout( Get_Fct_Show(this), this.iInterval);

Voila ça fonctionne nickel pour moi alors...
pour info je prépare une  source pour cela, tu en as la primeur...

Nota :
Le principe est expliqué à l'adresse suivante
http://developer.mozilla.org/fr/docs/Le_principe_de_fermeture_en_JavaScript:Utilisation_des_fermetures

;0)
Messages postés
10
Date d'inscription
jeudi 15 février 2007
Statut
Membre
Dernière intervention
18 mars 2010

Merci PetoleTeam. Mais ça ne marche pas chez moi.

En lisant le lien, j'ai modifié comme suit :
    this.startDiaporama = function()
    {
        var iInterval = this.iInterval;
        var refChangeImage = this.changeImage();

        this.oTimer = window.setInterval( "refChangeImage;", iInterval);
    }

J'ai aussi essayé :
        this.oTimer = window.setInterval( refChangeImage, iInterval);

        this.oTimer = setTimeout( "refChangeImage;", iInterval);


        this.oTimer = setTimeout( "efChangeImage, iInterval);


Comme au début, j'ai la 1ère image qui s'affiche, mais la suite ne défile pas.

Quand le lien dit "l’argument this ne correspond pas à l’objet lui-même", c'est bien ce que je comprends.
Messages postés
3426
Date d'inscription
lundi 26 décembre 2005
Statut
Membre
Dernière intervention
14 janvier 2011
14
B
onjour...
je suis surpris que l'exemple que je t'ai fourni ne fonctionne pas mais bon...peut être à cause du setTimeout au lieu du setInterval.

Rappel :
 setTimeout doit être réappellé, opération ponctuelle retardée, alors de setInterval instancie un timer qui relance la fonction et ce donc sans rappel.

Dans ton cas si tu lances le diaporama avec startDiaporama il te faut éfféctivement un setInterval, sinon avec le setTimeout il te faudrait le mettre dans la fonction changeImage.

Le probléme vient que tu déclares une variable en local, car avec var devant, alors qu'il la faut global pour qu'elle existe encore quand la fonction en cours ce termine.
Lorsque la fonction liée au setTimeout ou au setInterval ce déclenche après delai, la variable n'existe plus.

Donc plusieures solutions et entre autre

this.startDiaporama = function(){
  
oThis = this; // variable global sans le var devant
  //-- Avec les guillemets c'est une expression qui sera évaluée, pas de ; en fin
  this.oTimer = window.setInterval("oThis.changeImage()", this.iInterval); 
  //-- Sans les guillemets c'est un pointeur sur fonction
  this.oTimer = window.setInterval( oThis. changeImage, this.iInterval); 
}
je reste persuadé que l'application de
  this.oTimer = setInterval( Get_Fct_Show(this), this.iInterval);
doit fonctionner...

Tiens nous au courant...
;0)
Messages postés
10
Date d'inscription
jeudi 15 février 2007
Statut
Membre
Dernière intervention
18 mars 2010

Voici les résultats :

  //-- Avec les guillemets c'est une expression qui sera évaluée, pas de ; en fin
  this.oTimer = window.setInterval(" oThis. changeImage()", this.iInterval);
  //--> Marche

  //-- Sans les guillemets, avec les parentheses, pas de ; en fin
  this.oTimer = window.setInterval(oThis.changeImage(), this.iInterval);
  //--> Marche

  //-- Sans les guillemets, sans les parentheses, sans le ;
  this.oTimer = window.setInterval( oThis. changeImage, this.iInterval); 

  //--> Ne marche pas

Pour l'utilisation d'une fonction intermédiaire :
  this.oTimer = setInterval( Get_Fct_Show(this), this.iInterval);

  //--> Ne marche pas

Utilisation de setTimeout 
à la place de setInterval 
dans startDiaporama
et ajout de cette commande setTimeout   dans
changeImage
: ne marche pas.

Voila toutes les réponses aux tests demandés. J'ai donc gardé la 1ère solution mais j'ai un problème si j'ai 2 diaporamas sur la même page. Le problème vient de l'utilisation de oThis en variable globale.
Dans ma page HTML, j'ai 2 images. Pour chacune de ces images j'ai 2 instances de classes : diapo1 et diapo2.

Le 1er diaporama se déclanche dès que je pointe ma souris sur la 1ère image et que je sors de la zone de cette image.
Mais lorsque je fais la même chose sur la 2nde image, le 2ème diaporama se lance et le 1ère s'arrête.
Aussi sur le 2ème diaporama les intervalles de temps déclarés pour diapo1 et  diapo2 se chevauchent.
Lorsque je reviens sur le 1er, celui-ci reprends la relève et le 2nd s'arrête.

Donc l'utilisation d'une variable global oThis ne résoud pas mon affaire de classe.

Merci tout de même PetoleTeam pour le suivi de tes réponses. Chapeau !
Messages postés
3426
Date d'inscription
lundi 26 décembre 2005
Statut
Membre
Dernière intervention
14 janvier 2011
14
B
onjour...bonsoir plutôt quand c'est plus tard..

premier constat
 - tu bosses avec IE, car il ne supporte pas le passage sans les guillemets

second constat
 - c'est tout la limite de l'objet en variable globale, si plusieurs appel à la fonction sont faite il change de valeur entre chaque est cela devient vite la pagaille si les appels ne sont pas parfaitement alternés

troisième constat
 - c'est la raison de la solution avec la Get_Fct_Show(this) qui bien que sans guillement fonctionne sous IE et qui ne marche d'ailleur pas avec, ??? why IE ???

Le problème est peut être ailleurs
as tu une adresse ou l'on peut voir, ou le code si il n'y a pas 3513 lignes.

;0)
Messages postés
10
Date d'inscription
jeudi 15 février 2007
Statut
Membre
Dernière intervention
18 mars 2010

Je travaille sous Mozilla Firefox et parfois sous IE. Mais c'est vrai que les tests ci-dessus avaient été effectués sous Firefox et non sous IE.
L'exemple en ligne, je te le prépare dans la journée car pour l'instant je travaille en local.

J'ai trouvé une solution pas très jolie mais qui fonctionne : j'utilise la redondance.
Je m'explique :

1) Fichier Javascript :
// Constructeur
function Diaporama(sName, sHtmlImgName, iInterval)
{
    // Propriétés
    this.sName = sName; // Nom de l'instance de classe Diaporama
    // (...)

    this.startDiaporama = function()
    {
        this.timerID = window.setInterval( this.sName + ".changeImage()", this.iInterval); //marche
    }

}

2) Fichier HTML
<!-- (...) -->
<script language ="javascript">
var diapo1 = new Diaporama( "diapo1" , "IMG_Diaporama1", 1000);
var diapo2 = new Diaporama("diapo2", "IMG_Diaporama2", 3000);
</script>
<!-- (...) -->


<!-- (...) -->


<!-- (...) -->
Messages postés
3426
Date d'inscription
lundi 26 décembre 2005
Statut
Membre
Dernière intervention
14 janvier 2011
14
B
onjour...
solution pas très jolie mais qui fonctionne, est utilisée fréquement, c'est l'ESSENTIEL...

une autre solution du même type est de déclarer un compteur global que l'on incrément en entrant dans la constructeur, puis que l'on utilise pour initialise this.Obj

exemple :
var Diapo_Count= 0;
//----------------------
function Diaporama(.....){
  Diapo_Count ++;
  this.Obj = "Obj"+ Diapo_Count;
  eval( this.Obj +"=this");
  ....
  this.Start = function() {
    this.timerID = window.setInterval( this.Obj + ".changeImage()", this.iInterval);    }
}

cela revient en fait au même si ce n'est un paramètre de moins...

mais ce qui me turlupine quand même c'est que la soluce avec Get_Fct_Show(this) ne fonctionne pas pour toi

?0)
Messages postés
10
Date d'inscription
jeudi 15 février 2007
Statut
Membre
Dernière intervention
18 mars 2010

Merci PetoleTeam de cette solution plus jolie que la mienne. Au moins ça m'évite de rappeler mon instance de classe en paramètre de type chaîne. C'est plus propre d'éviter la redondance.
Ca ne résout pas le problème de l'utilisation de This dans setInterval ou set TimeOut mais ta dernière solution me suffit pour aboutir à mon but de réaliser une classe Diaporama.
Tout est dans la commande eval
que je n'ai pas encore bien maîtrisé. A lire quelques sites, cette commande est nouvelle et n'est très connue.

A propos de la solution Get_Fct_Show(this) j
e t'envoie l'adresse de ma page par MP.

Encore merci pour tes solutions proposées.
Messages postés
10
Date d'inscription
jeudi 15 février 2007
Statut
Membre
Dernière intervention
18 mars 2010

Salut PetoleTeam,

En fait c'est en t'écrivant mon MP, que j'ai compris d'où venait l'erreur à propos de  Get_Fct_Show(this)
.
J'ai fait un copier/coller bêtement :

//-- Création d'une fonction dans la zone globale
function Get_Fct_Change( o_){
  return( function(){o_.changeImage()});
// return l'adresse de la fonction
}

ensuite on fait l'appel de la façon suivante
  this.oTimer = setTimeout( Get_Fct_Show(this), this.iInterval);

Je t'envoie tout de même le lien au cas où tu as besoin de faire un test.
Messages postés
3426
Date d'inscription
lundi 26 décembre 2005
Statut
Membre
Dernière intervention
14 janvier 2011
14
B
onjour...
HOU LA le vrai BO
U
L
ET

on m'a pourtant toujours prévenu que quand on est dans une logique d'erreur il faut arrêter puis reprendre depuis le début.
1000 excuses pour cette faute de frappe aliant ton contexte et le mien.
on va pouvoir passer à autre chose...
Bonne continuation...
;0)