Existen varios trucos que permiten mejorar la usabilidad de los formularios en Sharepoint sin tener que meternos en personalizar los mismos.
Mediante algunos scripts podemos conseguir mejorar la experiencia de usuario y minimizar los posibles errores que pueda tener a la hora de rellenar un formulario.
En este caso, traemos tres scripts que aplicaremos en un ejemplo de un parte de horas:
- Por un lado, añadiremos un campo en blanco en un campo de tipo búsqueda, ya que Sharepoint no lo hace automáticamente para los campos que son obligatorios. Así, obligamos al usuario a rellenarlo y evitamos que se equivoque.
- También, modificaremos uno de esos combos para hacer que tenga la característica de «Autocompletar»
- Por último, introduciremos un script que genera un efecto cascada entre dos combos. Es decir, rellenará el segundo de los combos dependiendo de lo que se haya seleccionado en el primero.
Ilustración 1 Formulario por defecto
Añadir campo en blanco a campo tipo de búsqueda:
En este caso, se quiere meter un campo vacío en cliente, para que el usuario no pueda guardar el elemento sin antes haber seleccionado un cliente. El script también realiza una validación del campo.
Para ello, insertamos este script en un editor de contenido en el formulario. Habrá que modificar el nombre del campo en el que se quiere introducir el valor vacío:
function ObtenerDropDown(title) {
var dropdowns = document.getElementsByTagName('select');
for (var i = 0; i < dropdowns.length; i++) { if (dropdowns[i].title === title) { return dropdowns[i]; } } return null; } function ObtenerBotonOK() { var inputs = document.getElementsByTagName('input'); var len = inputs.length; var okButtons = []; for (var i = 0; i < len; i++) { if (inputs[i].type && inputs[i].type.toLowerCase() === 'button' && inputs[i].id && inputs[i].id.indexOf('diidIOSaveItem') >= 0) {
okButtons.push(inputs[i]);
}
}
return okButtons;
}
function AddVacioAlDropDown(oDropdown, text, value, optionnumber){
var options = oDropdown.options;
var option = document.createElement('OPTION');
option.appendChild(document.createTextNode(text));
option.setAttribute('value',value);
if (typeof(optionnumber) == 'number' && options[optionnumber]) {
oDropdown.insertBefore(option,options[optionnumber]);
}
else {
oDropdown.appendChild(option);
}
oDropdown.options.selectedIndex = 0;
}
function ObtenerClickEvent(element, newFunction) {
var clickFunc = element.onclick;
element.onclick = function(event){
if (newFunction()) {
clickFunc();
}
};
}
function MiFuncion() {
// Introducir nombre del dropdown
var fieldTitle = 'Cliente';
var dropdown = ObtenerDropDown(fieldTitle);
if (null === dropdown) {
alert('Unable to get dropdown');
return;
}
AddVacioAlDropDown(dropdown, '', '', 0);
var funcValidate = function() {
if (0 === dropdown.selectedIndex) {
alert("Por favor introduce un valor para " + fieldTitle + ".");
return false;
}
return true;
};
var okButtons = ObtenerBotonOK();
for (var b = 0; b < okButtons.length; b++) { ObtenerClickEvent(okButtons[b], funcValidate); } } _spBodyOnLoadFunctionNames.push("MiFuncion");
Una vez introducido el script, vemos que crea un elemento vacío en el campo de cliente:
Autocompletar en campo de tipo de búsqueda:
Para facilitar la búsqueda en un campo, vamos a introducir la funcionalidad de autocompletar para el combo del cliente.
El script es el siguiente:
$( function() {
$.widget( "custom.combobox", {
_create: function() {
this.wrapper = $( "" )
.addClass( "custom-combobox" )
.insertAfter( this.element );
this.element.hide();
this._createAutocomplete();
this._createShowAllButton();
},
_createAutocomplete: function() {
var selected = this.element.children( ":selected" ),
value = selected.val() ? selected.text() : "";
this.input = $( "" )
.appendTo( this.wrapper )
.val( value )
.attr( "title", "" )
.addClass( "custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left" )
.autocomplete({
delay: 0,
minLength: 0,
source: $.proxy( this, "_source" )
})
.tooltip({
classes: {
"ui-tooltip": "ui-state-highlight"
}
});
this._on( this.input, {
autocompleteselect: function( event, ui ) {
ui.item.option.selected = true;
this._trigger( "select", event, {
item: ui.item.option
});
},
autocompletechange: "_removeIfInvalid"
});
},
_createShowAllButton: function() {
var input = this.input,
wasOpen = false;
$( "" )
.attr( "tabIndex", -1 )
.attr( "title", "Show All Items" )
.tooltip()
.appendTo( this.wrapper )
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
})
.removeClass( "ui-corner-all" )
.addClass( "custom-combobox-toggle ui-corner-right" )
.on( "mousedown", function() {
wasOpen = input.autocomplete( "widget" ).is( ":visible" );
})
.on( "click", function() {
input.trigger( "focus" );
// Close if already visible
if ( wasOpen ) {
return;
}
// Pass empty string as value to search for, displaying all results
input.autocomplete( "search", "" );
});
},
_source: function( request, response ) {
var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
response( this.element.children( "option" ).map(function() {
var text = $( this ).text();
if ( this.value && ( !request.term || matcher.test(text) ) )
return {
label: text,
value: text,
option: this
};
}) );
},
_removeIfInvalid: function( event, ui ) {
// Selected an item, nothing to do
if ( ui.item ) {
return;
}
// Search for a match (case-insensitive)
var value = this.input.val(),
valueLowerCase = value.toLowerCase(),
valid = false;
this.element.children( "option" ).each(function() {
if ( $( this ).text().toLowerCase() === valueLowerCase ) {
this.selected = valid = true;
return false;
}
});
// Found a match, nothing to do
if ( valid ) {
return;
}
// Remove invalid value
this.input
.val( "" )
.attr( "title", value + " no se corresponde con ningún elemento" )
.tooltip( "open" );
this.element.val( "" );
this._delay(function() {
this.input.tooltip( "close" ).attr( "title", "" );
}, 2500 );
this.input.autocomplete( "instance" ).term = "";
},
_destroy: function() {
this.wrapper.remove();
this.element.show();
}
});
$("select[Title*='Cliente']").combobox();
} );
Y el resultado:
Efecto cascada entre campos tipo búsqueda:
Para facilitar el rellenado de formularios con campos de tipo LookUp, es recomendable utilizar este script de cascada para aquellos campos relacionados.
- En este caso se busca que en el combo de Proyectos únicamente aparezcan aquellos proyectos que estén ligados al cliente seleccionado en el combo superior. Así, facilitaremos la búsqueda al usuario:
$(document).ready(function() {
FuncionCascada({
campoPadreForm: "Cliente", //"Display Name" del campo de la lista en el que se pone el script que referencia al Padre (LookUp al padre)
listaHija: "Proyectos", //Nombre de la lista hija
campoLookUpHijo: "Title", //Nombre interno del campo de la lista hija a la que hace referencia el lookup del formulario que contiene el script (Campo objetivo del lookup al hijo)
campoHijoForm: "Proyecto", //"Display Name" del campo de la lista en el que se pone el script que referencia al hijo (LookUp al hijo)
campoPadreListaHija: "Cliente" //Nombre interno del campo en la lista hija que referencia al padre (lookup al padre)
});
});
function FuncionCascada(params)
{
var parent = $("select[Title='"+params.campoPadreForm+"'], select[Title='"+
params.campoPadreForm+" Campo requerido']");
$(parent).change(function(){
EjecutarFuncionCascada(this.value,params);
});
var currentParent = $(parent).val();
if (currentParent != 0)
{
EjecutarFuncionCascada(currentParent,params);
}
}
function EjecutarFuncionCascada(parentID,params)
{
var child = $("select[Title='"+params.campoHijoForm+"'], select[Title='"+
params.campoHijoForm+" Campo requerido']," +
"select[Title='"+params.campoHijoForm+" possible values']");
$(child).empty();
var options = "";
var call = $.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/Web/Lists/GetByTitle('"+params.listaHija+
"')/items?$select=Id,"+params.campoLookUpHijo+","+params.campoPadreListaHija+
"/Id&$expand="+params.campoPadreListaHija+"/Id&$filter="+params.campoPadreListaHija+
"/Id eq "+ parentID,
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=verbose"
}
});
call.done(function (data,textStatus, jqXHR){
for (index in data.d.results)
{
options += "
data.d.results[index][params.campoLookUpHijo]+"";
}
$(child).append(options);
});
call.fail(function (jqXHR,textStatus,errorThrown){
alert("Error obteniendo lista: " + params.listaHija + jqXHR.responseText);
$(child).append(options);
});
}
Una vez introducido el script, únicamente aparecerán los proyectos asociados al cliente:
Estos cambios habría que realizarlos tanto en los formularios de creación como en el de edición facilitando la carga de datos por parte de los usuarios. Aun así, hay que tener en cuenta que únicamente funcionarán en los formularios, nunca en la opción de modificación de la lista en modo Excel.
Espero haberos ayudado a mejorar la usabilidad en los formularios de Sharepoint.
¡Mantente atento a nuestros próximos post de Recursos Técnicos! ¡Nos vemos!