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.