En el artículo anterior hemos visto un uso básico del editor de DataTables. Tuvo un interesante valor didáctico, pero no nos valdría para un caso real de uso, ya que adolece de severas limitaciones. Por ejemplo, la fecha de ingreso de los miembros del personal no debería poder teclearse libremente, para que el usuario no pueda meter la pata. En su lugar, se debería mostrar un datepicker que obligue a respetar un formato de fecha en la introducción de datos. Lo mismo ocurre con el salario. No debe aparece el signo del euro en el campo, y debemos forzar un formato correcto de introducción de datos. Además, antes de enviar el formulario, en los casos de nuevo registro y edición, debemos hacer una comprobación previa. Si algún dato no se ajusta al formato esperado (por ejemplo, letras en el campo del salario). Si algo no está bien, debemos avisar al usuario, y cancelar el envío del formulario, hasta que todos los campos pasen la validación. Eso le da un toque mucho más profesional a nuestra aplicación. Por supuesto, nunca podremos evitar completamente que el usuario meta la pata. Algunos usuarios lo hacen cada vez que tienen la más mínima oportunidad de ello, pero paliaremos mucho esos errores.
Presta especial atención a este artículo porque vamos a conocer muchas opciones de configuración nuevas. No son difíciles de entender. De hecho, estoy racionalmente seguro de que, cuando leas el código, y lo pruebes, lo entenderás casi sin leer el texto del artículo. No obstante, si es mucha materia nueva y te la detallaré paso a paso.
LOS SCRIPTS SECUNDARIOS
Los scripts secundarios no presentan novedades respecto a los del artículo anterior. Simplemente los hemos renombrado a datos_externos_editor_03.php
y crud_editor_03.php
. Otro elemento que tampoco cambia respecto al script anterior es la tabla de personal que empleamos. Estos tres elementos te los he dejado para descargar en un comprimido en este enlace. Simplemente, descomprímelo, guarda los scripts en la ruta correspondiente en tu ordenador (localhost/datatables
, si sigues la misma nomenclatura que yo en los artículos) y, si no la tienes, importa la tabla en MySQL.
EL SCRIPT PRIMARIO
Aquí es donde se cuece todo. Lo hemos llamado articulo_editor_03.php
, y su listado es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Uso de DataTables</title> <!-- El CSS de jQuery UI --> <link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"> <!-- El CSS de DataTables --> <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/jszip-2.5.0/pdfmake-0.1.18/dt-1.10.12/af-2.1.2/b-1.2.2/b-colvis-1.2.2/b-flash-1.2.2/b-html5-1.2.2/b-print-1.2.2/cr-1.3.2/fc-3.2.2/fh-3.1.2/kt-2.1.3/r-2.1.0/rr-1.1.2/sc-1.4.2/se-1.2.0/datatables.min.css"/> <!-- El CSS de Bootstrap --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <!-- El editor --> <link rel="stylesheet" type="text/css" href="editor/css/editor.dataTables.css"> </head> <body> <br> <div class="container"> <div class="row"> <div class="col-sm-12"> <table id="tabla_de_personal" class="table display table-striped table-bordered"> <thead> <tr> <th>NOMBRE</th> <th>APELLIDO</th> <th>CARGO</th> <th>CIUDAD</th> <th>INGRESO</th> <th id="cabeceraDeSalario">SALARIO</th> </tr> </thead> <tbody> </tbody> </table> </div> </div> </div> <!-- jQuery --> <script language="javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <!-- jQuery UI --> <script language="javascript" src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script> <!-- El JavaScript de DataTables --> <script language="javascript" type="text/javascript" src="https://cdn.datatables.net/v/dt/jszip-2.5.0/pdfmake-0.1.18/dt-1.10.12/af-2.1.2/b-1.2.2/b-colvis-1.2.2/b-flash-1.2.2/b-html5-1.2.2/b-print-1.2.2/cr-1.3.2/fc-3.2.2/fh-3.1.2/kt-2.1.3/r-2.1.0/rr-1.1.2/sc-1.4.2/se-1.2.0/datatables.min.js"></script> <!-- El JavaScript de BootStrap --> <script language="javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <!-- El editor --> <script type="text/javascript" src="editor/js/dataTables.editor.js"></script> <!-- La librería moment.js para fechas --> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"></script> <!-- El código JavaScript --> <script language="javascript"> var objetoEditor = new $.fn.dataTable.Editor({ ajax: 'crud_editor_03.php', table: '#tabla_de_personal', idSrc: 'id', i18n: { create: { button: "Nuevo", title: "Crear nuevo registro", submit: "Grabar" }, edit: { button: "Editar", title: "Editar registro", submit: "Actualizar" }, remove: { button: "Borrar", title: "Borrar registro", submit: "Borrar", confirm: { _: "¿Estás seguro de eliminar estos %d registros?", 1: "¿Estás seguro de eliminar este registro?" } }, multi: { title: "Múltiples valores", info: "Los registros seleccionados contienen diversos valores para este campo. Para editar este campo con el mismo valor en los registros seleccionados, pulsa aquí. En caso conterario, los registros mantendrán sus valores individuales en este campo.", restore: "Restaurar los valores múltiples", noMulti: "Esta entrada puede ser modificada individualmente, pero no como parte de un grupo." }, datetime: { previous: 'Anterior', next: 'Siguiente', months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'], weekdays: ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb'] } }, fields: [ {label: 'Nombre:', name: 'nombre'}, {label: 'Apellido:', name: 'apellido'}, {label: 'Cargo:', name: 'cargo'}, {label: 'Ciudad:', name: 'ciudad'}, { label: 'F. Ingreso:', name: 'fecha_de_ingreso', type: 'date', def: function(){return new Date();}, dateFormat: 'dd-mm-yy', attr: {readonly:true}, opts:{ buttonImage:'editor/images/calendar.png', buttonImageOnly: true, buttonText: 'Elegir fecha', dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'], dayNamesMin: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá'], dayNamesShort: ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb'], firstDay: 1, monthNames: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'], monthNamesShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'], changeMonth: true, changeYear: true, prevText: "Anterior", nextText: "Siguiente" } }, { label: 'Salario anual:', name: 'salario_bruto_anual', fieldInfo: 'El salario debe ir como valor numérico, con dos decimales (incluso si son 00), separados por un punto.' }, ] }); objetoEditor.on('preSubmit', function(e, data, action){ if (action == 'remove') return true; // Se comprueba que el nombre tenga contenido, si no es multiedición. var dato_nombre = objetoEditor.field('nombre').val(); if (!objetoEditor.field('nombre').isMultiValue()) dato_nombre = dato_nombre.trim(); if (dato_nombre == "" && !objetoEditor.field('nombre').isMultiValue()){ objetoEditor.field('nombre').error('Debes teclear el nombre.'); objetoEditor.field('nombre').focus(); return false; } else { objetoEditor.field('nombre').error(''); } // Se comprueba que el apellido tenga contenido, si no es multiedición. var dato_apellido = objetoEditor.field('apellido').val(); if (!objetoEditor.field('apellido').isMultiValue()) dato_apellido = dato_apellido.trim(); if (dato_apellido == "" && !objetoEditor.field('apellido').isMultiValue()){ objetoEditor.field('apellido').error('Debes teclear el apellido.'); objetoEditor.field('apellido').focus(); return false; } else { objetoEditor.field('apellido').error(''); } // Se comprueba que el cargo tenga contenido, si no es multiedición. var dato_cargo = objetoEditor.field('cargo').val(); if (!objetoEditor.field('cargo').isMultiValue()) dato_cargo = dato_cargo.trim(); if (dato_cargo == "" && !objetoEditor.field('cargo').isMultiValue()){ objetoEditor.field('cargo').error('Debes teclear el cargo.'); objetoEditor.field('cargo').focus(); return false; } else { objetoEditor.field('cargo').error(''); } // Se comprueba que la ciudad tenga contenido, si no es multiedición. var dato_ciudad = objetoEditor.field('ciudad').val(); if (!objetoEditor.field('ciudad').isMultiValue()) dato_ciudad = dato_ciudad.trim(); if (dato_ciudad == "" && !objetoEditor.field('ciudad').isMultiValue()){ objetoEditor.field('ciudad').error('Debes teclear la ciudad.'); objetoEditor.field('ciudad').focus(); return false; } else { objetoEditor.field('ciudad').error(''); } // Se comprueba que el nombre tenga contenido, si no es multiedición. Además, se comprueba que se ajuste a formato. var dato_salario_bruto_anual = objetoEditor.field('salario_bruto_anual').val(); if (!objetoEditor.field('salario_bruto_anual').isMultiValue()) dato_salario_bruto_anual = dato_salario_bruto_anual.trim(); if (dato_salario_bruto_anual == "" && !objetoEditor.field('salario_bruto_anual').isMultiValue()){ objetoEditor.field('salario_bruto_anual').error('Debes teclear el salario bruto anual.'); objetoEditor.field('salario_bruto_anual').focus(); return false; } else { objetoEditor.field('salario_bruto_anual').error(''); } if (dato_salario_bruto_anual != parseFloat(dato_salario_bruto_anual).toFixed(2) && !objetoEditor.field('salario_bruto_anual').isMultiValue()){ objetoEditor.field('salario_bruto_anual').error('El salario bruto anual no tiene el formato correcto.'); objetoEditor.field('salario_bruto_anual').focus(); return false; } else { objetoEditor.field('salario_bruto_anual').error(''); } return true; }); var objetoDataTables_personal = $('#tabla_de_personal').DataTable({ "language": { select: { rows: { _: "%d registros seleccionados", 0: "No se han seleccionado registros", 1: "1 registro seleccionado" } }, "emptyTable": "No hay datos disponibles en la tabla.", "info": "Del _START_ al _END_ de _TOTAL_ ", "infoEmpty": "Mostrando 0 registros de un total de 0.", "infoFiltered": "(filtrados de un total de _MAX_ registros)", "infoPostFix": "(actualizados)", "lengthMenu": "Mostrar _MENU_ registros", "loadingRecords": "Cargando...", "processing": "Procesando...", "search": "Buscar:", "searchPlaceholder": "Dato para buscar", "zeroRecords": "No se han encontrado coincidencias.", "paginate": { "first": "Primera", "last": "Última", "next": "Siguiente", "previous": "Anterior" }, "aria": { "sortAscending": "Ordenación ascendente", "sortDescending": "Ordenación descendente" } }, "lengthMenu": [[5, 10, 20, 25, 50, -1], [5, 10, 20, 25, 50, "Todos"]], "iDisplayLength": 10, "bServerSide": true, "sAjaxSource": "datos_externos_editor_03.php", "columns" : [ {"data": 'nombre'}, {"data": 'apellido'}, {"data": 'cargo'}, {"data": 'ciudad'}, {"data": 'fecha_de_ingreso'}, {"data": 'salario_bruto_anual', className: "text-right"} ], "columnDefs": [ { "targets": 5, "render": function (data) { return salaryFormat(data); } } ], select: true, dom: 'Bfrtipl', buttons: [ {extend: 'create', editor: objetoEditor}, {extend: 'edit', editor: objetoEditor}, {extend: 'remove', editor: objetoEditor} ] }); $('label').addClass('form-inline'); $('select, input[type="search"]').addClass('form-control input-sm'); $('#cabeceraDeSalario').removeClass("text-right"); function salaryFormat(valorRecibido) { var separado = valorRecibido.split("."); var parteEntera = separado[0]; var unidades = new Array(); var fragmento; while (parteEntera > ""){ fragmento = parteEntera.substr(-3, 3); parteEntera = parteEntera.substr(0, parteEntera.length - 3); unidades.unshift(fragmento); } var valorFinal = unidades.join("."); if (separado.length > 1) valorFinal += ("," + separado[1]); valorFinal += " €"; return valorFinal; } </script> </body> </html> |
Vale.. Visto así impone un poco, pero ten en cuenta dos cosas. Primera. Sin el editor y sin la configuración que hacemos del mismo, obtener los resultados que obtenemos llevaría mucho más código, y muchísimo más tiempo de desarrollo. Y la segunda. Si has seguido todos los artículos de DataTables verás que tampoco es para llevarse las manos a la cabeza. Vamos a ir viendo que hacemos. No comentaremos tódo el código. Sólo las novedades de este artículo con respecto a lo que ya sabemos, que corresponden a las líneas resaltadas en el listado.
En las líneas 9
y 43
vemos que incluimos, por CDN, jQueryUI. Lo vamos a usar para el datepicker del campo relativo a la fecha de ingreso en los formularios de nuevo y edición.
En la línea 51
vemos que incluimos la librería de JavaScript moment.js
. Se trata de una librería JavaScript especializada en la gestión de datos de fecha y hora, que el editor de DataTables necesita si queremos poder darle a la fecha un formato adecuado en el formulario. Si no, por defecto, las fechas irán en el formato ISO 8601
que, si bien es lo mejor para las bases de datos y la operativa interna, desde luego no lo es para un formulario para el usuario. Dado que, como te digo, el editor va a necesitar esta librería, la incluimos antes de empezar a trabajar.
En el artículo anterior ya aprendimos a crear un objeto de la clase editor
, basado en el complemento editor de DataTables. Aquí vamos a empezar a ver novedades con respecto a aquél. Lo primero es la definición de los textos, en un idioma distinto del inglés, del campo de fecha, entre las líneas 85
y 90
:
datetime: {
previous: 'Anterior',
next: 'Siguiente',
months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
weekdays: ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb']
}
En este caso, no lo vamos a necesitar ya que, cómo hemos dicho, para la fecha vamos a usar el datepicker de jQueryUI. Estos textos serían relevantes si fuésemos a usar un campo de fecha HTML 5, que es un poco más “soso” a mi gusto. Los ponemos, únicamente, para que te conste como los incluiríamos si no fuéramos a usar jQueryUI.
Entre las íneas 97
y 119
vemos cómo definimos el campo de fecha:
{
label: 'F. Ingreso:',
name: 'fecha_de_ingreso',
type: 'date',
def: function(){return new Date();},
dateFormat: 'dd-mm-yy',
attr: {readonly:true},
opts:{
buttonImage:'editor/images/calendar.png',
buttonImageOnly: true,
buttonText: 'Elegir fecha',
dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
dayNamesMin: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sá'],
dayNamesShort: ['Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb'],
firstDay: 1,
monthNames: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
monthNamesShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'],
changeMonth: true,
changeYear: true,
prevText: "Anterior",
nextText: "Siguiente"
}
},
Las propiedades label
y name
se usan como en cualquier otro campo. Ninguna novedad en eso.
Atención. La propiedad buttonImage
hace referencia al icono que abre y cierra el datpicker. En las versiones actuales del editor el fabricante ha dejado de incluir la carpeta images
, por lo que deberás crear tú dicha carpeta e incluir en ella el icono adecuado. Puedes usar este mismo (), haciendo clic derecho sobre él y seleccionando
Guardar imagen como...
.
La propiedad type
se refiere, como sabes, al tipo de dato del campo. Con el valor date
le indicamos que es un campo de fecha.
La propiedad def
se refiere al valor por defecto. Si usamos el formulario para edición de un registro, en el campo ya hay un valor. Sin embargo, en el caso de usarlo para crear un nuevo registro, en el campo podemos querer que aparezca, por defecto, la fecha del día en curso, que es lo que indicamos aquí.
La propiedad dateFormat
establece el formato en que se mostrará la fecha en el formulario, y en el que el usuario debe introducirla. Y aquí es donde el editor necesita la librería moment.js
que decíamos antes. Si no la hemos incluido, esta línea dará un error de JavaScript, y lo que estamos haciendo no funcionará.
La propiedad attr
permite asociarle al campo cualquier atributo que pudiéramos usar en HTML, si estuviéramos creando el campo “a mano”. En este caso le asignamos el atributo readonly
, como el valor true
, porque, al ser un campo de fecha, queremos que el usario tenga que emplear el datepicker que le proporcionamos, y no pueda teclear nada directamente, para minimizar posibles errores.
Cuando el editor detecta que se ha incluido jQueryUI, automáticamente lo selecciona para el datepicker, por lo que no necesitamos indicárselo. Sin embargo, si es necesario establecer las opciones del datepicker de jQueryUI que estableceríamos si fuéramos a usarlo de modo independiente en un formulario cualquiera. En el caso del editor de DataTables, estas opciones se establecen en opts
, y corresponden con las del datepicker, que puedes ver en este enlace.
En la línea 123
vemos como definir una información complementaria a un campo, para que el usuario la lea. Lo que incluimos como contenido de la propiedad fieldInfo
se muestra, en una tipografía más reducida que la normal, debajo del campo al que le asociamos esta propiedad (en este ejemplo, el campo relativo al salario.
PREVALIDACIÓN EN EL LADO DEL CLIENTE
Lo que aparece a continuación, entre las líneas 128
y 194
es una validación previa de los datos introducidos, de modo que, si hay algún error (por ejemplo, un salario con letras) no se envíe el formulario para procesar. En su lugar, se informará al usuario, y se focalizará el campo que presente errores. Veamos cómo opera este mecanismo.
Los objetos creados sobre el editor de DataTables pueden detectar varios eventos, que iremos conociendo, mediante el método on()
. Este es similar, en cuanto a sintaxis y uso, a su homónimo de jQuery, pero orientado a su uso con los objetos editor específicamente, ya que puede detectar los eventos de estos. En este caso, detectamos el evento preSubmit
. Este evento se dispara cuando el usuario pulsa el botón de envío del formulario, y justo antes de que se efectúe dicho envío, lo que es ideal para validaciones, ya que, si no se validan correctamente los datos, se puede interrumpir el proceso de envió.
Además, el método on()
recibe, cómo segundo argumento, una función callback, que será la encargada de efectuar la validación. Esta recibe tres argumentos:
- El propio evento que se ha detectado.
- Los datos del formulario, en un sólo objeto.
- La acción que se estaba llevando a cabo en el momento de dispararse el evento.
Fíjate en la forma en que invocamos a este detector para el evento preSubmit
:
objetoEditor.on('preSubmit', function(e, data, action){
Como ves, se aplica, directamente, sobre el objeto que hemos creado para usar el editor de DatTables.
Dentro de la función de callback que empleamos para la validación, lo primero que hacemos es comprobar cual es la acción que se ha pedido, ya que, si es la de eliminar uno o más registros (remove
), no hay nada que prevalidar. En ese caso, se permite, directamente, el envío del formulario, así:
if (action == 'remove') return true;
Por lo tanto, todo lo demás que hay en la función sólo se empleará en caso de que la acción sea la creación de un nuevo registro (create), o la edición de uno o más registros (edit).
Lo siguiente que encontramos es una comprobación de que el nombre no esté vacío, o no contenga, únicamente, espacios en blanco. Empezamos recuperando el contenido del campo en una variable de JavaScript:
var dato_nombre = objetoEditor.field('nombre').val();
A partir de aquí hay que tener en cuenta si estamos haciendo una edición de múltiples registros. Eso lo averiguamos con el método isMultiValue()
. Si estamos haciendo una edición de múltiples registros, y hemos tecleado algo en el campo nombre, este método devuelve un valor true
. Se la edición es de un sólo registro, o si, en caso de múltiples registros, no hemos tecleado nada, para respetar los contenidos originales de este campo, el método devuelve false
. También devuelve false
si la operación es create
. Si este método devuelve false
, debemos recortar los espacios al principio y al final del contenido del campo, así:
if (!objetoEditor.field('nombre').isMultiValue()) dato_nombre = dato_nombre.trim();
Si el campo está vacío y el método isMultiValue()
devuelve false, es cuando se debe entender que hay un error, y debemos informar de ello al usuario. El método error()
coloca un texto en rojo debajo del campo que le indicamos. Además, debemos focalizar ese campo e interrumpir el envío. Si no hay error, debemos eliminar el mensaje en rojo de debajo del campo, y pasar a comprobar el siguiente campo:
if (dato_nombre == "" && !objetoEditor.field('nombre').isMultiValue()){
objetoEditor.field('nombre').error('Debes teclear el nombre.');
objetoEditor.field('nombre').focus();
return false;
} else {
objetoEditor.field('nombre').error('');
}
El resto de los campos, si sigues el código, se validan de la misma manera. En el momento que se detecte un error, se informará al usuario, y se interrumpirá el envío.
Un caso más delicado es el del último campo, relativo al salario. No sólo se valida cómo los demás, sino que, además, se comrueba que sea un número en coma flotante, con el punto cómo separador de los decimales, y con dos cifras decimales, así:
var dato_salario_bruto_anual = objetoEditor.field('salario_bruto_anual').val();
...
if (dato_salario_bruto_anual != parseFloat(dato_salario_bruto_anual).toFixed(2) && !objetoEditor.field('salario_bruto_anual').isMultiValue()){
objetoEditor.field('salario_bruto_anual').error('El salario bruto anual no tiene el formato correcto.');
objetoEditor.field('salario_bruto_anual').focus();
return false;
} else {
objetoEditor.field('salario_bruto_anual').error('');
}
Y ya está. Si hemos superado las validaciones, se envía (por fín) el formulario, y se procesa con el script secundario adecuado, que ya conocemos del artículo anterior.
Los scripts y la base de datos puedes descargarlos de este enlace.
Pingback: El editor de DataTables (IV). Datos de múltiples tablas. – El desván de Jose