Ejemplo para filtrar un contents desde campos de una colección


Vamos a ver cómo podemos filtrar con unos campos de una colección, otra colección colocada en forma de contents (subformulario), para ver los resultados de la búsqueda sobre la marcha.

También veremos como podemos manejarlo todo con botones, en este caso de tipo gráfico, sin utilizar los botones por defecto, incluso hasta para salir de la colección.

Aquí está la imagen de lo que se pretende:

1.- Definimos la colección de Clientes:

<!-- 
	- Previamente en el AppWizard.xml habremos definido el atributo mode="1", para entrar en la coleccion en edicion.
	- editmask ="2" para que solo se pueda editar, no dejamos siquiera salir, esto lo haremos con un boton.
	- notab="true" para que no salgan pestañas en la edición y así ganamos también espacio de pantalla.
	- special="true" para que no haga caso ni de la sql ni de objname y updateobj (ni lee ni graba en BD)
-->
<coll name="ClientesMode1" editmask="2" notab="true" special="true" cell-bgcolor="#FFFFFF" title="las Clientes" nostopreplica="true" sql-debug="false" 
	sql="SELECT c.*, 0 as MAP_BUSCAR FROM ##PREF##Clientes a" objname="Clientes" updateobj="Clientes" progid="ASData.CASBasicDataObj" 
	fontsize="8" editwidth="60" editheight="81">
 
<!-- 
	- Aunque no vayamos a mostrar pestañas, siempre tiene que haber un group
	- bgcolor="#CEE3F6,#FFFFFF,#FFFFFF,#CEE3F6" para poner un degradado de color de fondo al frame (contenedor)
	- Hacemos un frame(contenedor) para agrupar los campos de busqueda y poder ocultarlos o mostrarlos cuando se pulse
	  el botón del filtro(embudo).
	- disablevisible="MAP_BUSCAR=1", la visibilidad del grupo estará en funcion del campo MAP_BUSCAR, cuando MAP_BUSCAR=1
	  NO estarán visibles los campos del filtro(al estar dentro del frame oculto) y cuando MAP_BUSCAR=0 estarán visibles.
-->
	<group name="Cliente" id="1"></group>
	<frame name="id1" framebox="true" bgcolor="#CEE3F6,#FFFFFF,#FFFFFF,#CEE3F6" width="100%" disablevisible="MAP_BUSCAR=1" />
 
	<prop name="MAP_ETIQUETA" visible="1" group="1" type="TL" fieldsize="20" labelwidth="20" title="CLIENTES" class="etiquetatitulo"></prop>
 
<!-- ************************************************************
	CAMPOS DE ENLACE CON OTRAS COLECCIONES
 ************************************************************  -->
	<prop name="MAP_IDRUTA" group="1" frame="id1" size="10" fieldsize="10" type="N" visible="0" mapcol="Rutas" mapfld="ID" onchange="refresh" />
 
<!-- ************************************************************
	CAMPOS MAP_ PARA EL FILTRO (NO SE GRABAN EN BD)
	- El campo MAP_CODRUTA1 esta oculto y lo utilizaremos para buscar la ruta que pertenece al dia de hoy.
	- El campo MAP_BUSCAR esta oculto y lo vamos a utilizar para definir la visibilidad de los campos del filtro (frame)
 ************************************************************  -->
	<prop name="MAP_BUSCAR" group="1" frame="id1" size="10" fieldsize="10" type="N" visible="0" />
	<prop name="MAP_CODRUTA1" visible="0" frame="id1" group="1" type="T" fieldsize="30" size="30" labelwidth="8" class="textoprograma" onchange="refresh">Codigo:</prop>
	<prop name="MAP_RUTA" visible="7" frame="id1" group="1" type="T" fieldsize="30" size="30" labelwidth="8" linkedto="MAP_IDRUTA" linkedfield="DESCRIPCION" class="textoprograma" showinline="true">Ruta:</prop>
	<prop name="MAP_CODCLIBUS" visible="7" frame="id1" group="1" type="T" fieldsize="30" size="30" labelwidth="8" class="textoprograma">Codigo:</prop>
	<prop name="MAP_DESCCLIBUS" visible="7" frame="id1" group="1" type="T" fieldsize="30" size="30" labelwidth="8" class="textoprograma">Nombre:</prop>
 
<!-- ************************************************************
	BOTONES Y CONTENTS DE RESULTADOS
	- En los botones tenemos  method="ExecuteNode(buscar)" indicando el nodo que se va a ejecutar cuando se pulse el botón.
	- En el content tenemos el locked="true" y mask="0" para que no se pueda tocar ni editar ningún registro del contents
	- Es importante el onchange en el contents para que refresque cuando cambiemos el filtro
 ************************************************************  -->
	<button name="Buscar" caption="Buscar" group="1" visible="1" method="ExecuteNode(buscar)" class="boton" img="search.png" width="50" height="50" />
	<button name="Nofiltro" caption="NoFiltro" group="1" lmargin="22" visible="1" method="ExecuteNode(nofiltro)" newline="false" class="boton" img="nofilter.bmp" width="50" height="50" />
 
	<prop name="@ContentClientes" group="1" type="Z" contents="ClientesRutas" lines="6" locking="true" locked="true" onchange="refresh255" editmodal="true" forceonchange="true" mask="0"></prop>
	<contents name="ClientesRutas" src="ClientesRutas" mask="0"></contents>
 
	<button name="Salir" caption="Salir" group="1" tmargin="3" visible="1" method="ExecuteNode(salir)" class="boton" img="salir.png" width="50" height="50" />
 
<!-- ************************************************************
	- El nodo method name=“ExecuteNode”, es un nodo de sistema, y actualmente solo es obligatorio en el Framework de PC.
	  hay que ponerlo siempre que tengamos al menos un botón. (solo se pone una vez y siempre es igual)
 ************************************************************  -->
	<method name="ExecuteNode">
		<param name="P1" type="T" value="" />
	</method>
 
<!-- ************************************************************
	- En las rutas tendremos un CODIGO del dia (1-Domingo, 2-Lunes...)
	- Obtenemos el numerico del dia de hoy y lo buscamos en el campo CODIGO de la colección RUTAS
 ************************************************************  -->
	<before-edit>
		<action name="runscript">
			<script language="VBScript">
				this("MAP_CODRUTA1")=cstr(Weekday(now))
				set obj=AppData.GetCollection("Rutas")("CODIGO",CStr(This("MAP_CODRUTA1")))
				if not obj is nothing then
					this("MAP_IDRUTA")=obj("ID")
				end if
				set obj =nothing
 
				createFilter
			</script>
		</action>
	</before-edit>
 
	<buscar>
		<action name="runscript">
			<script language="VBScript">
				createFilter
				this("MAP_BUSCAR")=0
			</script>
		</action>
	</buscar>
 
	<nofiltro>
		<action name="runscript">
			<script language="VBScript">
				this("MAP_BUSCAR")=1
			</script>
		</action>
	</nofiltro>
 
	<salir>
		<action name="runscript">
 			<script language="VBScript">
				AppData.FailWithMessage -11888,"##EXIT##"
			</script>
		</action>
	</salir>
 
</coll>

Para la función createFilter, esta podemos definirla en un fichero .vbs externo

function addCriteria(sOut,sField,sData)
	if len(cstr(sData))>0 then
		if len(sOut)>0 then
			sOut=sOut+" AND "
		end if
		addCriteria=sOut+sField+" LIKE '%"+sData+"%'"
	else
		addCriteria=sOut
	end if
end function
 
function createFilter()
	dim sSearch
	sSearch=""
	sSearch=addCriteria(sSearch,"IDRUTA",this("MAP_IDRUTA"))
	sSearch=addCriteria(sSearch,"MAP_CODCLI",this("MAP_CODCLIBUS"))
	sSearch=addCriteria(sSearch,"MAP_NOMCLI",this("MAP_DESCCLIBUS"))
	this.contents("ClientesRutas").filter=sSearch
end function

2.- Definimos las colecciones de rutas y el contents de resultados:

    <coll name="Rutas" notab="true" cell-bgcolor="#FFFFFF" xeditmask="0" nomenmask="0" title="las Rutas" nostopreplica="true" sql-debug="false" sql="SELECT a.* FROM ##PREF##Rutas a" objname="Rutas" updateobj="Rutas" filter="(BAJA=0 OR BAJA IS NULL)" progid="ASData.CASBasicDataObj" fontsize="8" editwidth="60" editheight="81" autorefresh="true">
      <group name="General" id="1"></group>
      <prop name="CODIGO" visible="7" group="1" type="T" fieldsize="30" size="30" labelwidth="8" class="textoprograma">Codigo</prop>
      <prop name="DESCRIPCION" visible="7" group="1" type="T" fieldsize="30" size="30" labelwidth="8" class="textoprograma">Matricula</prop>
      <prop name="BAJA" visible="0" group="1" type="N" fieldsize="30" size="30" labelwidth="8" class="textoprograma">Baja</prop>
    </coll>
 
<!-- ************************************************************
	- Esta colección es igual a la de clientes
	- check-owner="false" dependent="false" para que no intente asociarlo con una cabecera.
	- Asegurarse de poner los visible="7" para que los campos salgan visibles en modo contents
 ************************************************************  -->
    <coll name="ClientesRutas" notab="true" cell-bgcolor="#FFFFFF" show-toolbar="false" editmask="8" forprint="false" title="los clientes" sql="SELECT cr.*,c.CODIGO AS MAP_CODCLI,c.NOMBRE AS MAP_NOMCLI,c.POBLACION AS MAP_POBLCLI,
    c.DIRECCION AS MAP_DIRCLI,c.TELEFONO AS MAP_TELCLI, r.CODIGO AS MAP_CODRUTA, r.DESCRIPCION AS MAP_DESCRUTA
    FROM ((##PREF##ClientesRutas cr	
    LEFT OUTER JOIN ##PREF##Clientes c ON cr.IDCLIENTE=c.ID)
    LEFT OUTER JOIN ##PREF##Rutas r ON cr.IDRUTA=r.ID)" check-owner="false" dependent="false" objname="ClientesRutas" updateobj="ClientesRutas" progid="ASData.CASBasicDataObj" editwidth="50" editheight="50" fontsize="8">
      <group name="General" id="1" bgcolor="#FFFFFF"></group>
      <prop name="IDCLIENTE" group="1" size="10" fieldsize="10" type="N" visible="0" mapcol="Clientes" mapfld="ID" />
      <prop name="IDRUTA" group="1" size="10" fieldsize="10" type="N" visible="0" mapcol="Rutas" mapfld="ID" />
      <prop name="MAP_CODCLI" visible="7" group="1" type="T" fieldsize="12" size="50" labelwidth="10" linkedto="IDCLIENTE" linkedfield="CODIGO" class="textoprograma">Cod Cli:</prop>
      <prop name="MAP_NOMCLI" visible="7" group="1" type="T" fieldsize="12" size="50" labelwidth="10" linkedto="IDCLIENTE" linkedfield="NOMBRE" class="textoprograma">Nomb Cli:</prop>
      <prop name="MAP_POBLCLI" visible="7" group="1" type="T" fieldsize="12" size="50" labelwidth="10" linkedto="IDCLIENTE" linkedfield="POBLACION" class="textoprograma">Pobl Cli:</prop>
      <prop name="MAP_DIRCLI" visible="7" group="1" type="T" fieldsize="12" size="50" labelwidth="10" linkedto="IDCLIENTE" linkedfield="PROVINCIA" class="textoprograma">Dir Cli:</prop>
      <prop name="MAP_TELCLI" visible="7" group="1" type="T" fieldsize="12" size="50" labelwidth="10" linkedto="IDCLIENTE" linkedfield="TELEFONO" class="textoprograma">Tfno Cli:</prop>
      <prop name="MAP_CODRUTA" visible="7" group="1" type="T" fieldsize="12" size="50" labelwidth="10" linkedto="IDRUTA" linkedfield="CODIGO" class="textoprograma">Cod Ruta:</prop>
      <prop name="MAP_DESCRUTA" visible="7" group="1" type="T" fieldsize="12" size="50" labelwidth="10" linkedto="IDRUTA" linkedfield="DESCRIPCION" class="textoprograma">Desc Ruta:</prop>
    </coll>