Controles creados dinámicamente

La generación dinámica de contenidos en páginas web es una técnica cada vez más difundida, ya que las nuevas tecnologías web como Ajax, y la web 2.0, nos han acostumbrado a revisar constantemente nuestras páginas favoritas (portales, foros, blogs...) en busca de nueva información.

Inserciones básicas

La forma básica de insertar nuevo contenido en una página es creando un nuevo elemento (createElement), añadirle contenido (crearteTextNode), modificar sus atributos y estilos a nuestro gusto, e insertarlo con los métodos appendChild o insertBefore.

A continuación ponemos el código para insertar a principio de una capa, nuevas capas creadas dinámicamente:

var contador = 0;
function nuevaCapa()	{
	elemento = document.createElement("div");
	elemento.appendChild(document.createTextNode("elemento " + contador));
	elemento.id = "elemento" + contador;
	elemento.style.backgroundColor = (contador++ % 2 == 0) ? "#dfdfdf" : "#fdfdfd";
	with	(document.getElementById("contenedor"))
		(hasChildNodes()) ? insertBefore(elemento, firstChild): appendChild(elemento);
}

Se puede ver el script anterior funcionando a continuación.




Si bien esta técnica funciona en todos los navegadores DOM, tiene algunas dificultades si se trata de controles de formularios, ya que en concreto, en los navegadores "explorer" no es posible su referenciación a partir de su atributo name (obligatorio en aquellos controles donde ponemos información para su procesamiento).

Nota: Otra forma de insertar nuevos contenidos, muy usado en aplicaciones ajax, es mediante innerHTML, aunque no nos detendremos en ello por no ser estándar.

El problema de los controles

La forma de modificar los atributos de cualquier etiqueta html, es simplemente poner ese elemento, seguido de un punto y a continuación el atributo en cuestión; cuando esos atributos no son propios del elemento (inventados), deberemos asignarlo usando el método setAttribute, o mediante otras formas que no vienen al caso. Así que después de crear un nuevo control debería ser suficiente la técnica mencionada para asignarle un nombre:

var contador = 0;
function nuevoControl()	{
	control = document.createElement("input");
	control.name = "nuevoInput";
	control.type = "text";
	control.value = "nuevo contenido";
	document.forms.miFormulario.appendChild(control);
}

Pero lamentablemente esta técnica, como ya hemos anticipado, no nos permite obtener su valor con la siguiente instrucción;

contenido = document.forms.miFormulario.nuevoInput.value;

Aunque el problema solo existe en explorer, debemos procurar que nuestros códigos funcionen correctamente en todos los navegadores, así que veremos qué debemos hacer.

Cómo se soluciona

La verdad es que aunque los controles no los reconozca el curioso navegador, al enviar el formulario nos encontramos que las variables llegan a destino correctamente; así que si no necesitamos referenciar nuestros nuevos controles tal vez sea preferible crearlos del tipo "hidden", o con su atributo readOnly activado; y si se tratase de un campo editable, podemos referenciarlo por su atributo id.

La alternativa que funciona correctamente en todos los navegadores es clonando un control con su atributo name asignado.

<div style="display: none" >
<input type="text" name="nuevoInput" id="control" />
</div>

La forma de crear el nuevo control debe modificarse entonces:

function nuevoControl()	{
	control = document.getElementById("control").cloneNode(true);
	control.id = "nuevoControl";
	control.value = "nuevo contenido";
	document.forms.miFormulario.appendChild(control);
}

Viendo ambos códigos, podemos apreciar que ninguno de ellos tiene mayor complejidad.

Algunas notas adicionales

Como conclusión destacamos que el único perjuicio del último código es la innecesaria existencia de una etiqueta oculta, y que según el número de controles nuevos que necesitemos, mayor será el número de controles ocultos que deberemos tener.

A favor de este código diremos que en el momento que necesitemos validar un formulario con campos creados dinámicamente, no tendremos que hacer ninguna "pirueta" para conseguir que sea fiable en todos los navegadores; simplemente referenciamos el control por su nombre, dependiendo directamente del propio formulario:

formulario.nuevoInput.value

Enlaces relacionados

Podemos ver en el artículo Revisar las imágenes antes de subirlas una forma de limpiar un control del tipo file, creando un control nuevo y eliminando el anterior.

También es interesante la página para Crear elementos dinámicamente de JavierB, miembro de los Foros del web.

Sobre la especificación DOM nivel 3, nos remitimos a w3.org.