Problema con SELECT en IE8

kraneok

Si, trabajando para un cliente que quiere IE8, increible pero cierto.
Problema: cargo un SELECT en base a la opción que se selecciona en otro SELECT, bien, este SELECT, pinta las opciones que vienen del back y se ven, correcto.
Cambio la opción en el primer SELECT, esta vez, no devuelve ninguna opción, pero uala, las opciones que vinieron antiguamente, siguen ahí. Examino el DOM, y efectivamente, el segundo SELECT no contiene ningún elemento, pero sin embargo, puedes verlos en el navegador.

IE8 parece ser que no refresca bien la UI del segundo SELECT, ¿ alguna forma de forzar a repintar el SELECT ?.

Gracias de antemano. Estoy muy quemado jejeje.

B

Usas jQuery? Se supone que con cualquier versión 1.x debería poder lidiar con el puto IE8

1 respuesta
kraneok

#2 Uso jQuery, para IE8, 1.9.1, pero nada no funciona. He de decir que estos componentes, tanto el primer como el segundo SELECT, se pintan de forma dinámica al abrir una pestaña, pues se deben cargar ambos en base a otro valor.

kraneok

Le he metido la 1.11 y nada, sigue igual. Ya no se que mas hacer la verdad.

B

Pfff huele a onSubmit y a recargar con backend xD

1 respuesta
kraneok

#5 Explicate xddd

B

o onChange() llevo mucho sin tocar front, pero vamos el caso es que cuando salte el evento de cambio en el select que decide el contenido del otro refresque la pagina pasando por backend con los valores nuevos

1 respuesta
kraneok

#7 Eso es lo que hace ahora mismo, un combo depende de otro. Pero no actualiza la UI IE8 y se ven los antiguos en el navegador, si entras al DOM, ves que están los nuevos.

B

#1 Yo uso jquery, y no tengo ningún problema con IE 8

Repasa tu código o simplemente haz algo así:

$(selectorPrimerSelect).change(function(){
        llenarSegundoSelect();
})

Esto te debría funcionar.

Donde llenarSegundoSelect() es algo tal que así:

function llenarSegundoSelect( idCombo, listObjJson ) {

var opts = $('#'+idCombo).prop('options');
			
//añadimos uno vacio		
opts[opts.length] = new Option( "", "" );

$.each(listObjJson, function (i, item) {
	opts[opts.length] = new Option( item.nombre, item.id );
});

   // Añadimos un valor por defecto
if (listObjJson.length > 0)
{
	$('#'+idCombo).val(listObjJson[0].id);
}
}

Comprueba en tu código que no te esté fallando la manera de rellenar el segundo array.

Si te sigue sin funcionar, lanza desde la consola de debug lo siguiente ( una vez te cargue la pagina ):

$(selectPrimero).trigger("change");

Esto lo que hace es lanzar un evento change del primer select. ( A ver si va a ser que no te este lanzando el onChange )....

1 respuesta
kraneok

#9
Este es el codigo de mis select, ahora te explico.
La dependencia entres combos es muy sencilla. Cada combo se instancia y se almacena la referencia de su instancia en el atributo data de el mismo.

Cada combo tiene varios atributos importantes: data-mcontrol-name="" data-mcontrol-dependency="" y data-mcontrol-dependency-injection="". ¿ Por qué ?, por que son combos generados dinámicamente y a mi no se me ocurre otra forma de conectar unos con otros, que indicandole a un combo en el nivel en el que esta, con el data-mcontrol-dependency-injection="". Es decir, si se generan en una tabla 10 registros, y dinamicamente se generan dos combos por cada registro. En el registro uno tendremos :
Combo1

data-mcontrol-name="ControlX" data-mcontrol-dependency-injection="0" data-mcontrol-dependency=""

Combo2

data-mcontrol-name="ControlY" data-mcontrol-dependency-injection="0" data-mcontrol-dependency="ControlX"

¿ Esto que va a hacer ?. Cuando ControlY se instancie, va a buscar la instancia llamada ControlX0, y le metera un método onChange, para cuando el ControlX cambie, Y lo detected, obtenga el elemento seleccionado y haga la petición al servidor con ese elemento seleccionado.

Esto funciona bien, de hecho, los combos relacionados que son estáticos funciona perfectamente, son los dinámicos los que no tiran.

MSelect = function(control, defs, row) {
		var _this = this;
		
	this.element 			 = $(control);
			
	this.defs 				 = defs;
	this.apids 				 = this.defs.apids || "";
	this.field 				 = this.defs.findField;
	this.dependency			 = this.element.attr("data-mcontrol-dependency");
	this.injection			 = this.element.attr("data-mcontrol-dependency-injection");
	this.dependencyQuery	 = "";
	this.dependencyFindField = this.defs["dependencyFindField"];
	this.datasource 		 = [];
	this.initValue  		 = (this.element.attr('data-mcontrol-init-value') !== undefined) ?
							 	$(row).find(".mtd[data-initfield]").attr('data-initfield') : null;
							 	
	this.prechargeValue      = $(control).attr('data-mcontrol-precharge-value');

	this.constructor();
};

MSelect.prototype = {
		
	_selectPrechargeValue : function () {
		var _this = this;
		if (_this.prechargeValue !== undefined && _this.prechargeValue !== "")
			_this.element.find("option[value=" + _this.prechargeValue + "]").prop("selected", true);
	},
		
	/**
	* 
	*/
	_loadData : function() {
		var _this = this;
		if (_this.apids !== "") {
			
			var completeQuery = "?"; 
			
			if (_this.initValue !== undefined && _this.initValue !== null)
				completeQuery += "idCompany=" + _this.initValue.split("-")[0];
			
			if (_this.dependencyQuery !== "")
				completeQuery += (completeQuery.length > 1) ? '&' + _this.dependencyQuery : _this.dependencyQuery;
			
			$.getJSON("list/" + _this.apids + ".json" + completeQuery, function(data) {
				_this.datasource  = [];
				_this.element.empty();
									
				_this.datasource.push({value : "", member : " " });			
				if (data.length != 0){
					$.each(data, function(i, e) {
						_this.datasource.push({
							value  : e[_this.defs.value],
							member : e[_this.defs.member]
						});
					});
				}
							
				_this._paintData();
				_this._selectPrechargeValue();

			});
			
		}else
		{
			$.each(_this.defs["data"], function(i, e) {
				_this.datasource.push({
					value  : e["value"],
					member : e["member"]
				});
			});
			_this._paintData();
			_this._selectPrechargeValue();
		}
		
		
	},

	_paintData : function() {
		var _this = this;
		
		$.each(_this.datasource, function(i, e) {
			var opt = $('<option value=' + e['value'] + '>'
					+ e['member'] + '</option>');
			
			_this.element.append(opt);
		});
	},

	getControlType : function () {
		return 'mselect';
	},
	clear : function() {
		var _this = this;
		_this.element.empty();
	},

	getFindField : function() {
		var _this = this;
		return _this.field;
	},

	getSelectedItem : function() {
		var _this = this;
		return _this.element.val();
	},
	getSelectedMember : function() {
		var _this = this;
		return _this.element.find ('option:selected').text ();
	},
	getExtraFindField : function() {
		var _this = this;
		if (_this.defs["extrafindfield"])
			return _this.defs["extrafindfield"];
	},
	getDependencyFindField : function () {
		var _this = this;
		return _this.dependencyFindField;
	},
	resetSelectedValue : function () {
		var _this = this;
		_this._selectPrechargeValue();
		_this.element.triggerHandler('change');
	},
	clean : function () {
		var _this = this;
		_this.element.val('');
	},

	constructor : function() {
		var _this = this;
					
		/// SUPER IMPORTANTE
		/// Este bloque de código contiene toda la lógica de la dependencia entres controles de tipo combos
		/// Porfavor, antes de tocar nada avisar a @delamata
		///
		/// El primero paso comprueba que si el control que se está instancido
		if (_this.dependency != undefined && _this.dependency !== "" &&
			_this.injection  != undefined && _this.injection  !== "") {
							
			var dependencies 	= _this.dependency.split("-");
			var lastDependency	= "[data-mcontrol-name=" + dependencies [dependencies.length - 1] + "][data-mcontrol-dependency-injection=" +  _this.injection + "]"; // Control always depend of the last dependency control
							
			$(lastDependency).on('change', function () {
														
				// Se limpia la cadena con la que se filtra
				_this.dependencyQuery = "";
									
				var lastDepenObj = $(lastDependency).data(dependencies [dependencies.length - 1] + _this.injection);
				
				if (lastDepenObj.getSelectedItem() !== null && lastDepenObj.getSelectedItem() !== "") {
					// Se genera la nueva cadena de búsqueda en función de los valores de las dependencias
					$.each(dependencies, function (index, dependencyField) {
						var completeDependencyControlName = dependencyField + _this.injection;
						var controlObj = $("[data-mcontrol-name=" + dependencyField + "][data-mcontrol-dependency-injection=" +  _this.injection + "]").data(completeDependencyControlName);
						
						_this.dependencyQuery += (controlObj.getSelectedItem() !== "") ? 
								controlObj.getDependencyFindField() + "=" + controlObj.getSelectedItem() : "";
								
						if (index != dependencies.length - 1) {
							_this.dependencyQuery += "&";
						}
						
					});
											
					_this._loadData();
				}else
				{
					_this.element.empty();
					_this.element.triggerHandler ('change');
				}
			});
		}else
		{
			_this._loadData();
			_this._combosRelations();
		}
	}
}


1 respuesta
B

#10 La función que recupera los datos, entiendo que es sincrona, no? A ver si lo vas a tener como asíncrono...

1 respuesta
kraneok

#11 Es asíncrona. Recupera los datos, crea el datasource y lanza el _paintData, que es el que resetea el combo y mete los nuevos elementos.

kraneok

Bueno, si a alguien le interesa he conseguido darle una solución. Para forzar IE8 a que repinte algun elemento del DOM como un SELECT, tan solo se le debe de reinicializar el tamaño, siempre en píxeles y además, uuna vez que haya sido cargado.

Es decir: se carga el combo con los nuevos elementos options, y se le hace al SELECT algo similar a esto, dependiendo de con que se esté trabajando para manejar DOM.

$('select').css('width', $(select).width() + 'px');

Usuarios habituales