lunes, 23 de marzo de 2009

Ajustando valores a controles ListFormField (al cargar) desde la QueryString

Objetivo:
Ajustar valores por defecto en controles obteniendolos desde la QueryString
Receta:
Para ajustar correctamente el valor obteniendolo de la QueryString, hemos de usar javascript.
Hay que tener cuidado al cambiar los ID de los controles desde el sharepoint designer, porque el codigo del DataBind es generado y utiliza funciones con el nombre ff33,ff34,... (ffNUMERO) y se cargará el valor en el control pero al guardar los valores y hacer el commit desde el formActionButton, no se guardan los valores. Por lo que recomiendo usar los nombres que asigna Sharepoint designer si no se entiende bien el codigo.

----

<script type="text/javascript">
// Este Javascript ajusta el valor por defecto de un LookupField// Hay que pegarlo en el NewForm dentro del tag PlaceHolderMain

_spBodyOnLoadFunctionNames.push("fillDefaultValues");

function fillDefaultValues() {

var qs = location.search.substring(1, location.search.length);
var args = qs.split("&"); var vals = new Object();
for (var i=0; i < args.length; i++) {
var nameVal = args[i].split("=");
var temp = unescape(nameVal[1]).split('+');
nameVal[1] = temp.join(' ');
vals[nameVal[0]] = nameVal[1];
}

getTagFromIdentifier("input","idEmpleado").value=vals["IDEMPLEADO"];
// setFieldValueFromFieldName("idEmpleado", vals["IDEMPLEADO"]); Esto funciona bien para los campos Lookup
setFieldValueFromFieldName("IdPuesto", vals["IDNUEVOPUESTO"]);
setLabelValueFromFieldName("lblIdEmpleado", vals["IDEMPLEADO"]);
}

function setFieldValueFromFieldName(fieldName,value){
if (value == undefined) return;
var theSelect = getTagFromIdentifierAndTitle("input","TextField",fieldName); theSelect.value=value;
}
function setLabelValueFromFieldName(fieldName,value){ if (value == undefined) return;
var theSelect = getTagFromIdentifier("span",fieldName);
theSelect.value=value; theSelect.innerText=value; theSelect.Text=value;
}

function setLookupFromFieldName(fieldName, value) {
if (value == undefined) return;
var theSelect = getTagFromIdentifierAndTitle("select","Lookup",fieldName);
// Si el control tiene mas de 20 elementos en la lista se renderiza con ajax por lo que hay que seleccionarlo de otra manera
// ya que se renderiza como input no como select
if (theSelect == null) {
var theInput = getTagFromIdentifierAndTitle("input","",fieldName);
ShowDropdown(theInput.id);
//this function is provided by SharePoint
var opt=document.getElementById(theInput.opt);
setSelectedOption(opt, value); OptLoseFocus(opt);
//this function is provided by SharePoint
} else {
setSelectedOption(theSelect, value);
}
}

function setSelectedOption(select, value) {
var opts = select.options;
var l = opts.length;
if (select == null) return;
for (var i=0; i < l; i++) {
if (opts[i].value == value) {
select.selectedIndex = i;
return true;
}
}
return false;
}
function getTagFromIdentifier(tagName, identifier) {
var len = identifier.length;
var tags = document.getElementsByTagName(tagName);
for (var i=0; i < tags.length; i++) {
var tempString = tags[i].id;
if (identifier == "" tempString.indexOf(identifier) == tempString.length - len) {
return tags[i];
}
}
return null;
}
function getTagFromIdentifierAndTitle(tagName, identifier, title) {
var len = identifier.length;
var tags = document.getElementsByTagName(tagName);
for (var i=0; i < tags.length; i++) {
var tempString = tags[i].id;
if (tags[i].title == title && (identifier == "" tempString.indexOf(identifier) == tempString.length - len)) {
return tags[i];
}
}
return null;
}
function getTagFromTitle(tagName, title) {
var tags = document.getElementsByTagName(tagName);
for (var i=0; i < tags.length; i++) {
if (tags[i].title == title) {
return tags[i];
}
}
return null;
}
function queryString(parameter) {
var loc = location.search.substring(1, location.search.length);
var param_value = false;
var params = loc.split("&");
for (i=0; i<params.length;i++) {
param_name = params[i].substring(0,params[i].indexOf('='));
if (param_name == parameter) {
param_value = params[i].substring(params[i].indexOf('=')+1)
}
}
if (param_value) {
return param_value;
} else {
return false;
//Here determine return if no parameter is found
}
}
</script>

Forma Directa de acceso a QueryString con JSRequest (Nativo en Sharepoint):

<script>
JSRequest.EnsureSetup();
var itemId = JSRequest.QueryString["PageView"];
alert(´Query String - ´ + itemId);
itemId = JSRequest.FileName;
alert(´Current Page - ´ + itemId); itemId = JSRequest.PathName;
alert(´Current Path - ´ + itemId);
</script>


RECOMENDACIÓN:
Si encadenáis listas con lookup usados como clave foránea, os recomiendo renderizar los controles como TEXTBOX en vez de como sharepoint ListFormField ya que seguramente queréis ocultar los campos con ID.De lo contrario veréis como se despliega el combo y a medida que vais teniendo mas datos, se ralentiza la página.

http://www.robertomarcos.com/

4 comentarios:

  1. En mi intento de no morirme, tratando de pasar el valor de la QueryString al Lookup-Field, lo estoy llevando mal. Ya he perdido mucho tiempo y no consigo encontrar la pista clave en Google. Tras varios intentos de adaptar tu script, ahora el valor viene asignado, pero la query no se ejecuta, hasta que no doy a la tecla "enter" o "return" y con el cursor en el lookup field.
    Tienes alguna idea?
    Gracias, Martin, BCN

    Esto es mi script:
    _spBodyOnLoadFunctionNames.push('fillDefaultValues');


    function setFieldValueFromFieldName(fieldName, value) {
    if (value == undefined) return;
    var theInput = getTagFromIdentifierAndTitle("Input","","SetID");
    theInput.value=value;
    }

    function fillDefaultValues() {
    var qs = location.search.substring(1, location.search.length);
    var args = qs.split("&");
    var vals = new Object();
    for (var i=0; i < args.length; i++) {
    var nameVal = args[i].split("=");
    var temp = unescape(nameVal[1]).split('+');
    nameVal[1] = temp.join(' ');
    vals[nameVal[0]] = nameVal[1];
    }
    setFieldValueFromFieldName("SetID", vals["Id"]);
    }

    function getTagFromIdentifierAndTitle(tagName, identifier, title) {
    var len = identifier.length;
    var tags = document.getElementsByTagName(tagName);
    for (var i=0; i < tags.length; i++) {
    var tempString = tags[i].id;
    if (tags[i].title == title && (identifier == "" || tempString.indexOf(identifier) == tempString.length - len)) {
    return tags[i];
    }
    }
    return null;
    }

    ResponderEliminar
  2. Lo primero que tienes que hacer es asegurarte que haces el Push a la funcion onLoad.
    Lo segundo es que no hayas cambiado el id al control, y si lo has hecho asegurate que la función del databind esta correctamente ajustada con el nuevo id, de lo contrario aunque carga el valor y lo ves, el dato no se guarda.
    Lo tercero es que pongas un boton de sharepoint y te asegures que llama al "_commit"

    ¿Que tipo de campo estas usando y como lo estas renderizando?, La funcion que mejor resultados me da es la que esta usando el ID en vez del fieldname, es un poco mas directo

    Este es el campo renderizado como FormField:
    <SharePoint:FormField runat="server" id="ff33{$Pos}" controlmode="New" fieldname="Articulo" __designer:bind="{ddwrt:DataBind('i',concat('ff33',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Articulo')}" />

    Esta es la linea de la funcion fillDefaulValues que ajusta el valor:
    getTagFromIdentifier("input","ff37_new").value=vals["ID_ARTICULO"];

    Este es el boton de aceptar:
    <input type="button" value="Aceptar" name="btnTopSave" onclick="{ddwrt:GenFireServerEvent(concat('__commit;__redirect={',$RedirectLoc,'}'))}"/>

    Esto funciona correctamente.

    Te aseguro que el focus del control no es determinante.

    ResponderEliminar
  3. Me olvidaba comentar que esto esta situado en la pagina newForm.aspx de la lista.

    ResponderEliminar
  4. Gracias por tu respuesta inmediata; aunque me hace sentir aún mas perdido. No estoy trabajando con listas de FormFields, sino con bases de datos SQL en Formview, pero en Sharepoint debería ser lo mismo, una vez establecido el Binding. Si me encuentrara "off-topic" me perdones porfa...

    Estoy enlazando dos paginas; la primera es un listado (GridView) de fichas de la base de datos. la segunda es la vista detallada de la ficha (FormView). clicando en una linea del listado, quiero que el enlace me lleve a la vista detallada.

    He podido modificar tu script y me hace casi todo lo que pedía: Pasar el valor del QueryString a traves la url al campo que controla la ejecución del Query. Esto es de tipo input normal
    input type="submit" title="SetID" name="SetID" />

    su vinculación con el query, viene definida en SqlDataSource.
    SelectParameters>
    asp:formparameter FormField="SetID" Direction="Input" Name="Id" />
    /SelectParameters>

    Asi que el campo de control se carga con el valor del query string, pero no se ejecute la query de forma automatica. Hay que esforzar el submit del valor dando "enter"

    La identificación de los controles no me falla con spBodyOnLoadFunctionNames.
    No puedo insertar SharePoint:FormField porque el Designer no me deja...
    No intiendo la función del botón

    Sharepoint es un monstruo con infinitos posibilidades; pero ultimamente acabo siempre escribiendo muchos codigos, cogidos de todas partes y de lenguajes que manejo solo en parte... cuando funciona es halucinante, porque MOSS es muy potente. Quando no funciona te lleva a niveles de frustración desconocidas. Saludos Martin

    PS: El blog de repente no me deja postar codigo...

    ResponderEliminar