Valeur précédente retournée par ui.val dans le change

Request description

Bonjour, j’ai un souci sur un champ que j’essaie de mettre à jour dynamiquement en fonction d’un autre, en front sur l’interface.

J’ai fait un script JS qui a l’air similaire à cette solution : Pb de valarisation d'un attribut par contrainte dans le cas d'un update - #4 by Francois

// CrbPcaDossier front side hook
(function(ui) {
	if (!ui) return;
	var app = ui.getAjax();
	// Hook called by each object instance
	Simplicite.UI.hooks.CrbPcaDossier = function(o, cbk) {
		try {
			console.log("CrbPcaDossier hooks loading...");
			var p = o.locals.ui;
			if (p && o.isMainInstance()) {
				p.form.onload = function(ctn, obj, params) {
					var qpe = ui.getUIField(ctn, obj, "pcaDossierInstPartExt");
					var qpr = ui.getUIField(ctn, obj, "pcaDossierInstPartRegion");
					
					qpe.ui.on("change", function() {
						console.log("Valeur part ext : " +qpe.ui.val());
            			var valQpe=parseFloat(qpe.ui.val());
            			if (!isNaN(valQpe))
            				qpr.ui.val(100-valQpe);
					});
				};
			}
		} catch (e) {
			app.error("Error in Simplicite.UI.hooks.CrbPcaDossier: " + e.message);
		} finally {
			console.log("CrbPcaDossier hooks loaded.");
			cbk && cbk(); // final callback
		}
	};
})(window.$ui);

J’ai peut-être raté quelque chose mais ça ne fonctionne pas, j’obtiens la valeur précédente de mon champ qpe au lieu de celle qui vient d’être changée.

J’ai affiché qpe.ui.val() dans la console pour confirmer qu’il y avait bien décalage et pas juste un problème d’affichage, ici après avoir changé 50 en 30 :



Remettre immédiatement une nouvelle valeur retourne la valeur 30, et ainsi de suite.

Une idée de ce qui pourrait causer cela?
Merci

Bonjour,

Mettez un “debugger” dans votre code pour faire du pas à pas dans votre navigateur.

Vous pouvez aussi mettre le change sur l’input directement pour voir :

$(qpe.ui.input).change(function() {
   debugger
   let valQpe = $(this).val();
   ...
});

ou refaire le calcul sur “input” ou “keyup”…

Bonjour,

J’ai testé avec $(this) au lieu de la référence qpe définie hors de la fonction on change, et ça marche, j’ai bien la valeur actuelle. Maintenant que j’y pense c’est peut-être une mauvaise idée d’utiliser une référence qui vient d’en dehors de la fonction, même si dans l’exemple de l’autre sujet ça avait l’air de marcher avec “field”.

J’ai fait un affichage console des deux valeurs pour vérifier :

p.form.onload = function(ctn, obj, params) {
	var qpe = ui.getUIField(ctn, obj, "pcaDossierInstPartExt");
	qpe.ui.on("change", function() {
		var qpr = ui.getUIField(ctn, obj, "pcaDossierInstPartRegion");
		console.log("Valeur obtenue par ref : " + qpe.ui.val());
		console.log("Valeur obtenue par this : " +$(this).val());
		let valQpe=parseFloat($(this).val());
		if (!isNaN(valQpe))
		qpr.ui.val(100-valQpe);
	});
};

En debugger je vois 2 scopes onload, l’un avec qpr et “<this>” actualisé, et l’autre avec qpe. C’est peut-être lié?
image

En tout cas plus de problème avec ce code.
Merci!

Etrange, le formulaire a peut être redessiné la champ entre temps, car la référence de l’input a changé.

Il convient d’utiliser le getter getUIField au moment de lire/ecrire la valeur, il contient les selectors qui vont chercher l’input (ou autre) associé au champ dans le container de l’objet. Si on le fait trop top : le champ n’est pas forcement encore présent, mais je n’ai jamais vu de cas où il pointe sur un “vieil” input non affiché.

Avez vous plusieurs fois ce champs dans l’objet ou le formulaire ?
Je vais regarder avec votre exemple cette histoire de scope.

Votre code dans la démo donne bien la bonne valeur en testant un changement de code fournisseur :
image

Il y a quelque chose qui recharge votre input entre le moment où le formulaire est dessiné une première fois, et le change : doublon, contraintes, responsive… ?

Dans votre cas pour avoir la bonne référence, il faut la recharger, car utiliser “this” c’est parfois ambigu ou incompatible avec des fonctions lambda, ex :

p.form.onload = function(ctn, obj, params) {
	let f = "pcaDossierInstPartExt";
	ui.getUIField(ctn, obj, f).ui.on("change", () => {
		let v = ui.getUIField(ctn, obj, f).val();
		...
	});
};

Pas de doublon à ma connaissance dans le formulaire, des contraintes sur l’objet mais aucune censée impacter ce champ.

La seule chose que je vois l’impactant directement c’est un traitement dans le hook initUpdate de l’objet métier, qui détermine si le champ est visible et modifiable.

Il n’y a rien d’autre dans le script front de l’objet non plus, juste ce que j’ai mis dans la première capture.

Je viens de tester en chargeant le champ depuis la fonction elle-même et j’ai le même problème avec la nouvelle référence qu’avec la première, la valeur retournée est l’ancienne :

if (p && o.isMainInstance()) {
	p.form.onload = function(ctn, obj, params) {
		let qpe = ui.getUIField(ctn, obj, "pcaDossierInstPartExt");
		qpe.ui.on("change", function() {
			let pe = ui.getUIField(ctn, obj, "pcaDossierInstPartExt");
			let pr = ui.getUIField(ctn, obj, "pcaDossierInstPartRegion");
			let testVal = pe.ui.val();
			debugger
 			let valQpe=parseFloat(pe.ui.val());
 			if (!isNaN(valQpe))
			pr.ui.val(100-valQpe);
		});
	};
}

Ok donc ça reste inexpliqué.

au debuggez regarder sur quoi pointe pe.ui.input, et recherchez tous les pcaDossierInstPartExt dans la page et dans la définition de l’objet. Vous devez avoir un champ caché qui contient l’ancienne valeur dans le formulaire.

$(this) est bien l’élément du change, donc ça reste une bonne solution, mais ce serait bien de trouver pourquoi vous avez 2 inputs au lieu d’un.

Quel est le code de l’initUpdate au niveau de ce champ ?

Dans le pe.ui.input je vois juste une entrée si j’interprète bien :
image

En suivant le lien vers le node j’arrive bien sur le champ attendu

Le code initUpdate pour ce champ passe par une méthode dans un code partagé (via la zone d’attributs qui le contient) :

		//////////
		for(String zone_dossier_inst_ext : Z_DOSSIER_INST_EXT){
			CRB_PCA_GESTION_DROITS.setZoneUpdatableFields(this.getFieldArea(zone_dossier_inst_ext),statut.equals("50D_ENINSTRUCT")&&getGrant().hasResponsibility("APPLI_SIMPLICITE_PCA_INSTRUCTEUR_EXTERNE"));
		}

setZoneUpdateFields change la propriété modifiable du champ au besoin :

	public static void setZoneUpdatableFields(FieldArea zone,boolean droit) {
		//AppLog.simpleDebug("Updatable :"+zone.getName()+" "+droit);
		for (int i=0; i<zone.getFields().size(); i++){
			ObjectField car = zone.getFields().get(i);
			// si champs commentaire et en lecture seule ne sont jamais required
			if (car.getUpdatableDefault()!=ObjectField.UPD_READ_ONLY&&Tool.isEmpty(car.getRefFieldName())) car.setUpdatable(droit);								
		}
	}

Je pensais qu’il y en avait une autre pour la visibilité, mais pas directement parce que c’est la zone complète qui est rendue visible ou pas dans le initUpdate.

Il y a aussi un changement de propriété obligatoire ou non dans le preValidate, un peu sur le même principe.

Pas d’autre référence au champ dans le code a priori.

Alors aucune idée si c’est bien un même et unique champ. De mon point de vue, tous ces codes sont équivalents pour un input simple :

pe.ui.val()
// qui devient pour un texte simple
pe.ui.input.val()

// sinon du natif
pe.ui.input[0].value
this.value
$(this).val()

Regardez ce qu’ils vous donnent.
Le 1er verbe de Simplicité ui.val() est préférable dans un cas général car ne dépend pas du type/rendering du champ (input, radio, check, select, file, image, éditeur html… qui n’ont pas forcement un input).

PS vous n’avez pas précisé votre version.

Version 5.2.38

J’ai fait le test avec les différents codes :

	qpe.ui.on("change", function() {
						let pe = ui.getUIField(ctn, obj, "pcaDossierInstPartExt");
						let t1 = pe.ui.val();
						let t2 = $(pe.ui.input).val();
						let t3 = pe.ui.input.value;
						let t4 = this.value;
						let t5 = $(this).val();
						
						debugger

Donc $(pe.ui.input).val() , this.value et $(this).val() renvoient la valeur attendue.
Mais pe.ui.val() renvoie la valeur précédente, et pe.ui.input.value est indéfini…

Voilà à quoi ça ressemble dans le débugger :


Sous le “0” dans input par contre je vois bien un champ value, et c’est la bonne valeur 50.

Merci pour ton retour, j’ai enfin compris…

D’après ton debugger le champ est un big decimal, et la valeur utilisée est bigdec = “15.00” qui permet de stocker la valeur sans perte de précision sous forme de String (sinon en javascript on ne peut pas stocker plus que des float = double precision).

Dans le cas d’un change cette variable n’est pas bien actualisée et du coup ça explique l’effet retard de cette variable en front. On va voir pour améliorer ça pour que la valeur bigdec s’actualise correctement à chaque “keyup” ou “input”.

Par contre pourquoi utiliser un bigdecimal pour un champ %, un simple décimal 6,2 devrait convenir à votre besoin.

Et sinon pe.ui.input est déjà un objet jQuery donc un tableau, donc en fait c’est pe.ui.input[0].value pour accéder à la valeur native de l’input.

OK, effectivement on n’a pas d’intérêt à utiliser ce type, je l’ai modifié.

En fait après vérification dans notre cas on n’a probablement même pas besoin de décimale du tout, donc même entier suffira. Et je confirme, ui.val() est bien actualisé maintenant.

Merci !

This topic was automatically closed 60 minutes after the last reply. New replies are no longer allowed.