Grails parâmetros indexados
-
06-07-2019 - |
Pergunta
Eu tenho uma lista de objetos Team
que têm uma propriedade Integer seed
. Quero editar todas as sementes das equipes de uma só vez, em um único formulário. Estou certeza que Grails suporta parâmetros indexados, mas não posso fazê-lo funcionar.
Aqui está o que eu tenho, e ele funciona, mas eu estou saltando através de maneira muitos aros e tem de haver uma maneira melhor.
gsp:
<g:form action="setSeeds">
...
<g:each in="${teams}" status="i" var="team">
<input type="hidden" name="teams[${i}].id" value="${team.id}">
<input type="text" size="2" name="teams[${i}].seed" value="${team.seed}">
</g:each>
</g:form>
controlador:
def setSeeds = {
(0..<30).each { i ->
def team = Team.get(Integer.parseInt(params["teams[${i}].id"]))
team.seed = Integer.parseInt(params["teams[${i}].seed"])
}
redirect(action:list)
}
Não é horrível? Maneira muito barulho. Como posso fazer algo ao longo das linhas de:
params.teams.each { t ->
def team = Team.get(t.id)
team.seed = t.seed
}
Isto é, como faço para mapear params nomeado team[0].seed
, team[0].id
, team[1].seed
, team[1].id
a uma lista?
Na Stripes você pode apenas ter uma propriedade List<Team>
e ele vai funcionar. Eu não menos esperar de Grails! ; -)
Agradecemos antecipadamente a sua ajuda.
Solução 2
Eu finalmente descobri como fazer isso sem travessuras.
Esqueça o parâmetro oculto e só usar o ID da equipe no parâmetro semente. No GSP:
<g:form action="setSeeds">
...
<g:each in="${teams}" var="team">
<input type="text" size="2" name="teams.seeds.${team.id}"
value="${team.seed}">
</g:each>
</g:form>
Em seguida, no controlador:
params.teams.seeds.each { teamId, seed ->
def team = Team.get(teamId.toInteger())
team.seed = seed.toInteger()
team.save()
}
redirect(action:list)
funciona como um encanto.
Outras dicas
params
é mais do que um mapa regular, é um GrailsParameterMap
que automaticamente constrói estruturas sub-mapa com base na divisão dos nomes de parâmetro por ''. Você pode aproveitar este usando a seguinte gsp:
<g:form action="seed">
<g:each in="${teams}" status="i" var="team">
<input type="hidden" name="teams.${i}.id" value="${team.id}">
<input type="text" size="2" name="teams.${i}.seed" value="${team.seed}">
</g:each>
<g:submitButton name="update" value="Update" />
</g:form>
NB: não há nenhum [] nos atributos de nome. O controlador é agora muito simples usando alguma magia Grails preto:
log.error "params = ${params}"
params.teams.findAll {k,v -> !k.contains(".")}.each { k,v ->
bindData(Team.get(v.id), v)
}
O primeiro findAll
operação filtra todos os parâmetros com um interior ponto. O resto é um mapa de mapas segurando o ID de linha na k
eo id
e seed
em v
.
Espero que isso responde sua pergunta.
Em 2015 ....
Grails funciona um pouco diferente agora e você pode encontrar-se correndo para cordas em vez do esperado sub-maps.I tem algo a trabalho, fazendo
algo como ..
params.nested.each{
if(!it.getKey().contains('.')){
//to get a map rather than a string...
params.nested[it.getKey()];
}
};
EDIT: By The Way ...
entradas que têm o mesmo nome, como
<input name="item.choice" type="checkbox" value="3" />
< input name="item.choice" type="checkbox" value="4"/>
são colocados em uma lista se mais de um são submetidos. Então, se ambas as perguntas acima foram verificados
<input name="item.choice" type="checkbox" value="3" checked />
< input name="item.choice" type="checkbox" value="4" checked/>
Você deseja obter uma lista.
Mas se apenas um está marcada, você NÃO obtiver uma lista (pelo menos em grails verison eu uso), você recebe um valor único.
<input name="item.choice" type="checkbox" value="3" checked />
< input name="item.choice" type="checkbox" value="4" />
Isso significa que em um controlador, se eu fosse fazer algo como
params['item.choice'].each{
def item=Item.get(it)
}
Seria lançar um erro se apenas um item foi enviado. Uma maneira Groovy de contornar este problema é
([]+(params['item.choice']?:[])).each{
def item=Item.get(it)
}
Se o parâmetro é conjunto e não uma lista, ele coloca o valor na lista vazia; Se o parâmetro é definido e uma lista, o operador mais irá adicionar todos os valores individuais para a lista vazia; se o parâmetro não for definido, ele irá adicionar duas listas vazias juntos, o que cria uma única lista vazia.
Não sei se isso ajuda, mas você poderia usar um fecho com ele como:
<g:each in="${teams}">
<p>id: ${it.id}</p>
<p>seed: ${it.seed}</p>
</g:each>
Você provavelmente poderia construir uma lista a partir deste instaed de produzir html. ou construir o seu formulário com ele.