IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

jQuery Discussion :

Error: $.setValue() must not be called from an asynchronous callback.


Sujet :

jQuery

  1. #1
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 172
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 172
    Points : 7 422
    Points
    7 422
    Billets dans le blog
    1
    Par défaut Error: $.setValue() must not be called from an asynchronous callback.
    Bonjour,

    Je me heurte à un problème très certainement tout bête, mais je n'arrive pas à trouver de solution…

    J'utilise un logiciel déjà existant. Je n'ai pas la main sur son code à proprement parler.
    En revanche, je peux paramétrer, dans certains endroits, des bouts de code JavaScript à exécuter lors de certaines actions.

    J'ai donc ici un élément de type menu déroulant (mais un truc custom, pas un simple <select>).
    Dessus, je peux indiquer un "hook function", à savoir une fonction exécutée lorsqu'on change la valeur sélectionnée.

    Voici l'appel :

    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    u8.Custom.Affaire.FieldRunValidator($, "StadeAvancementAffaire");

    Ensuite, voici mon code :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
     
    (function () {
        u8.Custom.Affaire =
    	{
    		CheckMustFields: function (e, save)
    		{
    			// Tout un tas de bordel
    		},
    		FieldRunValidator: function (object, otherCheck)
    		{
    			this.CheckMustFields(object.widget, false);
    			if (otherCheck === "StadeAvancementAffaire") {
    				u8.Custom.Affaire.StadeAvancementAffaire(object);
    			}
    		},
    		StadeAvancementAffaire: function (e) {
    			// Recherche de la valeur dans la base, ainsi que la présence de dossiers
    			var uid = e.widget.model.getUid();
    			var nouveau_code = e.getValue("F7021");
     
    			u8.services.queries.execute({ statement: "select (F7021, OJ1.SeqNo, OJ1.F7180) from (OJ) where (ProjType='#1' and StatNo = '" + u8.Custom.Affaire.GetUidPart(uid, 0) + "'and SeqNo = '" + u8.Custom.Affaire.GetUidPart(uid, 1) + "') plus (OJ using link 2 as OJ1) where (ProjType='#2')", options: {}}, function (sender, args)
    			{
    				var ancien_code = args.resultSet.rows[0].values[0];
     
    				if (args.resultSet.rows[0].values[1] === "") {
    					// Pas de dossier : aucun contrôle
    				} else {
    					// Il y a au moins un dossier
     
    					var catalogField = u8.services.schema.getField("OJ", "F7021");
    					var nouveau_externalKey = u8.services.catalogs.codeToExternalKey(catalogField, nouveau_code);
    					var ancien_externalKey = u8.services.catalogs.codeToExternalKey(catalogField, ancien_code);
    					var nb_adju = 0;
    					for (var i = 0; i < args.resultSet.rows.length; ++i) {
    						nb_adju += args.resultSet.rows[i].values[2];
    					}
     
    					switch (ancien_externalKey) {
    						case "INTENTION":
    						case "AVANTPROJET":
    						case "APPELOFFRE":
    							if (nouveau_externalKey === "ADJUDICATION" || nouveau_externalKey === "COMMANDE") {
    								// cas 1
    								if (nb_adju !== 1) {
    									alert("Changement non autorisé : un dossier doit être déclaré \"Adjudicataire\"");
    									save = false;
    								}
    							}
    							break;
    						case "ADJUDICATION":
    						case "COMMANDE":
    							if (nouveau_externalKey === "INTENTION" || nouveau_externalKey === "AVANTPROJET" || nouveau_externalKey === "APPELOFFRE") {
    								// cas 2
    								if (nb_adju !== 0) {
    									alert("Changement non autorisé : un dossier est déclaré \"Adjudicataire\"");
    									save = false;
    								}
    							}
    							break;
    						default:
    							// Pas de valeur avant : aucun contrôle
    							break;
    					}
    				}
    			});
    		}
    	}
    })();

    Ce code, en l'état, fonctionne.

    Selon le cas 1 ou cas 2, j'ai bien une popup affichant le message d'erreur.

    Seulement, je souhaite aussi annuler la saisie.
    Pour se faire, je dois faire un e.setValue("F7021", ancien_code)Et là je me tape le message d'erreur :
    Error: $.setValue() must not be called from an asynchronous callback.
    J'ai cherché un peu et j'ai compris qu'il fallait que j'utilise un deferred.
    Seulement je ne comprends absolument pas la syntaxe.

    Voici ce que j'ai tenté :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
     
    		StadeAvancementAffaire: function (e) {
    			var ancien_code = "";
     
    			// Recherche de la valeur dans la base, ainsi que la présence de dossiers
    			var uid = e.widget.model.getUid();
    			var nouveau_code = e.getValue("F7021");
     
    			var deferred = jQuery.Deferred();
    			deferred.then(function(value) {
    				alert("Save : " + value);
    				if (value === false) {
    					e.setValue("F7021", ancien_code);
    				}
    			});
    			u8.services.queries.execute({ statement: "select (F7021, OJ1.SeqNo, OJ1.F7180) from (OJ) where (ProjType='#1' and StatNo = '" + u8.Custom.Affaire.GetUidPart(uid, 0) + "'and SeqNo = '" + u8.Custom.Affaire.GetUidPart(uid, 1) + "') plus (OJ using link 2 as OJ1) where (ProjType='#2')", options: {}}, function (sender, args)
    			{
    				var save = true;
    				ancien_code = args.resultSet.rows[0].values[0];
     
    				if (args.resultSet.rows[0].values[1] === "") {
    					// Pas de dossier : aucun contrôle
    				} else {
    					// Il y a au moins un dossier
     
    					var catalogField = u8.services.schema.getField("OJ", "F7021");
    					var nouveau_externalKey = u8.services.catalogs.codeToExternalKey(catalogField, nouveau_code);
    					var ancien_externalKey = u8.services.catalogs.codeToExternalKey(catalogField, ancien_code);
    					var nb_adju = 0;
    					for (var i = 0; i < args.resultSet.rows.length; ++i) {
    						nb_adju += args.resultSet.rows[i].values[2];
    					}
     
    					switch (ancien_externalKey) {
    						case "INTENTION":
    						case "AVANTPROJET":
    						case "APPELOFFRE":
    							if (nouveau_externalKey === "ADJUDICATION" || nouveau_externalKey === "COMMANDE") {
    								// cas 1
    								if (nb_adju !== 1) {
    									alert("Changement non autorisé : un dossier doit être déclaré \"Adjudicataire\"");
    									save = false;
    								}
    							}
    							break;
    						case "ADJUDICATION":
    						case "COMMANDE":
    							if (nouveau_externalKey === "INTENTION" || nouveau_externalKey === "AVANTPROJET" || nouveau_externalKey === "APPELOFFRE") {
    								// cas 2
    								if (nb_adju !== 0) {
    									alert("Changement non autorisé : un dossier est déclaré \"Adjudicataire\"");
    									save = false;
    								}
    							}
    							break;
    						default:
    							// Pas de valeur avant : aucun contrôle
    							break;
    					}
    				}
     
    				deferred.resolve(save);
    			});
     
    			return deferred.promise();
    		}

    Malheureusement, si le code entre bien dans le "then()" j'ai toujours le message d'erreur.

    Pourtant, la fonction StadeAvancementAffaire() n'est pas elle-même une méthode callback asynchrone, car je peux faire ça :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    		StadeAvancementAffaire: function (e) {
    			e.setValue("F7021", 1);
    		}
    Seul hic, mon "1", il je ne peux le récupérer que depuis la méthode asynchrone u8.services.queries.execute().
    Mon besoin, ce serait donc :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    		StadeAvancementAffaire: function (e) {
    			var res = null;
    			MaFonctionAynchroneQuiVaBien();
    			JAttendsLaFinDeMaFonctionAsynchroneQuiVaBien();
    			e.setValue("F7021", res);
    		}

    Un peu comme le Join() de C# pour attendre la fin d'un thread.

  2. #2
    Expert confirmé Avatar de Toufik83
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    2 451
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2012
    Messages : 2 451
    Points : 4 975
    Points
    4 975
    Par défaut
    Salut,
    as-tu essayé un truc du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    StadeAvancementAffaire: function (e) {
      var deferred=$.Deferred();
      u8.services.queries.execute({...},function(sender,args){
         ...
         ancien_code = args.resultSet.rows[0].values[0];
       })
      .done(function(value){
         deferred.resolve(value);
         console.log("Save : ", value);
         if (value === false) {
    	e.setValue("F7021", ancien_code);
         }
      });
      return deferred.promise();
    });
     
    /*ou en utilisant $.when() et $.then()*/ 
    StadeAvancementAffaire: function (e) {
      var deferred=$.Deferred();
      $.when(
         u8.services.queries.execute({...},function(sender,args){
           ...
           ancien_code = args.resultSet.rows[0].values[0];
         })
       ).then(function(value){
         deferred.resolve(value);
         console.log("Save : ", value);
         if (value === false) {
    	e.setValue("F7021", ancien_code);
         }
      });
      return deferred.promise();
    });

Discussions similaires

  1. Réponses: 6
    Dernier message: 11/08/2015, 15h15
  2. Réponses: 3
    Dernier message: 25/08/2014, 20h57
  3. Réponses: 2
    Dernier message: 28/11/2013, 19h59
  4. Réponses: 13
    Dernier message: 29/10/2011, 17h38
  5. Réponses: 5
    Dernier message: 12/12/2005, 14h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo