Pues la integración de acegi security a la aplicación de Grails, la verdad fue una maravilla hacerlo, no cuesta absolútamente nada de trabajo... ahora configurar el encadenamiento de unos selects en Grails es otra historia, pero bueno, nada que no pueda ser resuelto...
Primero necesitas agregar en el head de tu gsp, luego agregar los selects a encadenar en mi caso estoy encadenando 3 (bueno 2, el 3ro depende del 2do y el 2do del primero, algo bastante obvio, pero bueno uno nunca sabe, jeje)
<tr class="prop">
<td valign="top" class="name"><label for="organization.name">Organización:</label></td>
<td valign="top" class="value">
<g:select
optionKey="id"
optionValue="name"
name="organizationId"
id="organizationId"
from="${Organization.list()}"
onchange="${remoteFunction(
controller:'organization',
action:'ajaxGetCompanies',
params:'\'id=\' + escape(this.value)',
onComplete:'updateCompany(e)'
)}"
value="${person?.warehouse?.company?.organization?.id}"
>
</g:select>
<g:select
optionKey="id"
optionValue="name"
name="companyId"
id="companyId"
onchange="${remoteFunction(
controller:'company',
action:'ajaxGetWarehouses',
params:'\'id=\' + escape(this.value)',
onComplete:'updateWarehouse(e)'
)}"
value="${person?.warehouse?.company?.id}"
></g:select>
<g:select id="warehouseId" name="warehouse.id" value="${person?.warehouse?.id}"></g:select>
</td>
</tr>
Y luego un script al final para poder hacer la carga de los elementos que resulta de las búsquedas
<script>
function updateCompany(e) { // The response comes back as a bunch-o-JSON
var companies = eval("(" + e.responseText + ")") // evaluate JSON
if (companies) {
var rselect = document.getElementById('companyId')
// Clear all previous options
var l = rselect.length
while (l > 0) {
l--
rselect.remove(l)
}
// Rebuild the select
for (var i=0; i < companies.length; i++) {
var company = companies[i]
var opt = document.createElement('option');
opt.text = company.name
opt.value = company.id
try {
rselect.add(opt, null) // standards compliant; doesn't work in IE
} catch(ex) {
rselect.add(opt) // IE only
}
}
}
var cselect = document.getElementById('companyId')
var copt = cselect.options[cselect.selectedIndex]
${remoteFunction(controller:'company',action:'ajaxGetWarehouses',params:'\'id=\' + copt.value',onComplete:'updateWarehouse(e)')}
}
function updateWarehouse(e) { // The response comes back as a bunch-o-JSON
var warehouses = eval("(" + e.responseText + ")") // evaluate JSON
if (warehouses) {
var rselect = document.getElementById('warehouseId')
// Clear all previous options
var l = rselect.length
while (l > 0) {
l--
rselect.remove(l)
}
// Rebuild the select
for (var i=0; i < warehouses.length; i++) {
var warehouse = warehouses[i]
var opt = document.createElement('option');
opt.text = warehouse.name
opt.value = warehouse.id
try {
rselect.add(opt, null) // standards compliant; doesn't work in IE
} catch(ex) {
rselect.add(opt) // IE only
}
}
}
}
// This is called when the page loads to initialize company
var zselect = document.getElementById('organizationId')
var zopt = zselect.options[zselect.selectedIndex]
${remoteFunction(controller:'organization', action:'ajaxGetCompanies', params:'\'id=\' + zopt.value', onComplete:'updateCompany(e)')}
</script>
La tienes que poner al final para que carge el remoteFunction del final en el que busca las empresas y este a su vez manda llamar la búsqueda de almacenes... si solo necesitas dos quitas la segunda funcion (updateWarehouse) y el llamado a la misma desde la primera funcion (y el select) y lo puedes dejar como el último select, no es necesario que tenga tanta información. Regresando al ejemplo, aun nos falta hacer la búsqueda, tienes que ir al controlador de organizacion y crear sus cierres (o metodos para que atienda las peticiones ajax), y lo mismo con el controlador de empresa.
def ajaxGetCompanies = {
def org = Organization.get(params.id)
render org?.companies as JSON
}
Solo que para que esto funciona necesitas realizar un import al inicio de la clase
import grails.converters.*
class OrganizationController {
No necesitas lo de class Organiz... solo es un ejemplo de donde va... Y listo... debe de funcionar...
Nota: Si quieres copiar el código, lo vas a necesitar convertir, para esto lo copias... lo llevas a http://www.centricle.com/tools/html-entities/ y lo decodificas
Primero necesitas agregar
<tr class="prop">
<td valign="top" class="name"><label for="organization.name">Organización:</label></td>
<td valign="top" class="value">
<g:select
optionKey="id"
optionValue="name"
name="organizationId"
id="organizationId"
from="${Organization.list()}"
onchange="${remoteFunction(
controller:'organization',
action:'ajaxGetCompanies',
params:'\'id=\' + escape(this.value)',
onComplete:'updateCompany(e)'
)}"
value="${person?.warehouse?.company?.organization?.id}"
>
</g:select>
<g:select
optionKey="id"
optionValue="name"
name="companyId"
id="companyId"
onchange="${remoteFunction(
controller:'company',
action:'ajaxGetWarehouses',
params:'\'id=\' + escape(this.value)',
onComplete:'updateWarehouse(e)'
)}"
value="${person?.warehouse?.company?.id}"
></g:select>
<g:select id="warehouseId" name="warehouse.id" value="${person?.warehouse?.id}"></g:select>
</td>
</tr>
Y luego un script al final para poder hacer la carga de los elementos que resulta de las búsquedas
<script>
function updateCompany(e) { // The response comes back as a bunch-o-JSON
var companies = eval("(" + e.responseText + ")") // evaluate JSON
if (companies) {
var rselect = document.getElementById('companyId')
// Clear all previous options
var l = rselect.length
while (l > 0) {
l--
rselect.remove(l)
}
// Rebuild the select
for (var i=0; i < companies.length; i++) {
var company = companies[i]
var opt = document.createElement('option');
opt.text = company.name
opt.value = company.id
try {
rselect.add(opt, null) // standards compliant; doesn't work in IE
} catch(ex) {
rselect.add(opt) // IE only
}
}
}
var cselect = document.getElementById('companyId')
var copt = cselect.options[cselect.selectedIndex]
${remoteFunction(controller:'company',action:'ajaxGetWarehouses',params:'\'id=\' + copt.value',onComplete:'updateWarehouse(e)')}
}
function updateWarehouse(e) { // The response comes back as a bunch-o-JSON
var warehouses = eval("(" + e.responseText + ")") // evaluate JSON
if (warehouses) {
var rselect = document.getElementById('warehouseId')
// Clear all previous options
var l = rselect.length
while (l > 0) {
l--
rselect.remove(l)
}
// Rebuild the select
for (var i=0; i < warehouses.length; i++) {
var warehouse = warehouses[i]
var opt = document.createElement('option');
opt.text = warehouse.name
opt.value = warehouse.id
try {
rselect.add(opt, null) // standards compliant; doesn't work in IE
} catch(ex) {
rselect.add(opt) // IE only
}
}
}
}
// This is called when the page loads to initialize company
var zselect = document.getElementById('organizationId')
var zopt = zselect.options[zselect.selectedIndex]
${remoteFunction(controller:'organization', action:'ajaxGetCompanies', params:'\'id=\' + zopt.value', onComplete:'updateCompany(e)')}
</script>
La tienes que poner al final para que carge el remoteFunction del final en el que busca las empresas y este a su vez manda llamar la búsqueda de almacenes... si solo necesitas dos quitas la segunda funcion (updateWarehouse) y el llamado a la misma desde la primera funcion (y el select) y lo puedes dejar como el último select, no es necesario que tenga tanta información. Regresando al ejemplo, aun nos falta hacer la búsqueda, tienes que ir al controlador de organizacion y crear sus cierres (o metodos para que atienda las peticiones ajax), y lo mismo con el controlador de empresa.
def ajaxGetCompanies = {
def org = Organization.get(params.id)
render org?.companies as JSON
}
Solo que para que esto funciona necesitas realizar un import al inicio de la clase
import grails.converters.*
class OrganizationController {
No necesitas lo de class Organiz... solo es un ejemplo de donde va... Y listo... debe de funcionar...
Nota: Si quieres copiar el código, lo vas a necesitar convertir, para esto lo copias... lo llevas a http://www.centricle.com/tools/html-entities/ y lo decodificas
Comentarios