Grails索引参数

8
我是一名有用的助手,可以为您翻译文本。
我有一个Team对象列表,其中包含一个Integer seed属性。 我想在单个表单中同时编辑所有团队的种子。 我确信Grails支持索引参数,但我无法使其工作。
这是我的代码,它能够工作,但是我需要跨越太多障碍,肯定有更好的方法。
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>

控制器:

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)
}

这太糟糕了吧?噪音太多了。我该怎么做才能实现以下功能:
params.teams.each { t ->
  def team = Team.get(t.id)
  team.seed = t.seed
}

也就是说,我该如何将名为team[0].seedteam[0].idteam[1].seedteam[1].id的参数映射到一个列表中呢?
Stripes中,你只需要有一个List<Team>属性,它就可以正常工作。我希望Grails也能做到!;-)
4个回答

11

params不仅仅是一个普通的Map,它是一个GrailsParameterMap,会根据参数名称中的“.”自动构建子Map结构。您可以利用这个功能使用以下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>

注意:name属性中没有方括号。使用一些黑色的Grails魔法,控制器现在非常简单:

log.error "params = ${params}"
params.teams.findAll {k,v -> !k.contains(".")}.each { k,v ->
       bindData(Team.get(v.id), v)
}

第一个操作findAll过滤掉所有带有点的参数。剩下的是一个包含行ID在k,以及v中的idseed的映射图。

我希望这回答了你的问题。


2
我想知道是否还有其他人在使用grails 1.3.4时遇到了问题。与预期的子映射不同,我得到的是子映射的字符串表示形式。例如,params.toString() "[filters.1.value:123, filters:["1":["value":"123"], "1.value":"123"], action:list, controller:user]" - bcowdery
是的,我在2015年遇到了各种问题。似乎grails现在将所有参数值都返回为字符串,这使得像bcowdery几年前发现的'maplist'字符串几乎无用。 - user2782001

6

我终于想出了如何在不使用任何花招的情况下完成这项任务。

忘记隐藏参数,只需在种子参数中使用团队ID即可。在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> 

然后,在控制器中:

params.teams.seeds.each { teamId, seed ->
  def team = Team.get(teamId.toInteger())
  team.seed = seed.toInteger()
  team.save()
}
redirect(action:list)

完美地运作。

1

在2015年....现在Grails的工作方式略有不同,您可能会发现自己运行字符串而不是预期的子映射。我通过类似于以下方式使某些内容正常工作:
...

params.nested.each{
               if(!it.getKey().contains('.')){
                 //to get a map rather than a string...    
                  params.nested[it.getKey()];
               }
           };

编辑:顺便说一句...

具有相同名称的输入,例如:

  <input name="item.choice" type="checkbox" value="3" />
  < input name="item.choice" type="checkbox" value="4"/>

如果提交的内容超过一个,则将它们放入列表中。因此,如果上述两个都被选中。
   <input name="item.choice" type="checkbox" value="3" checked />
   < input name="item.choice" type="checkbox" value="4" checked/>

你会得到一个列表。

但是如果只有一个被选中,你将不会得到一个列表(至少在我使用的Grails版本中),而是会得到一个单一的值。

     <input name="item.choice" type="checkbox" value="3" checked />
     < input name="item.choice" type="checkbox" value="4" />

这意味着在控制器中,如果我想要做类似下面的操作:
  params['item.choice'].each{
          def item=Item.get(it)
  }

如果只提交一个项目,它会抛出错误。解决这个问题的一种聪明方法是

 ([]+(params['item.choice']?:[])).each{
         def item=Item.get(it)
 } 

如果参数被设置且不是一个列表,它将该值放入空列表中;如果参数被设置且为一个列表,加号操作符会将所有单个值添加到空列表中;如果参数未设置,则将两个空列表相加,创建一个单一的空列表。


这是为什么?为什么嵌套的子地图会出错? - U47

-1

不确定这是否有帮助,但您可以像这样使用闭包:

<g:each in="${teams}">
     <p>id: ${it.id}</p>
     <p>seed: ${it.seed}</p>
</g:each>

你可以从这里构建一个列表,而不是输出HTML,或者用它来构建你的表单。

我已经使用闭包来构建一个表单。问题是,如何在控制器中检索索引参数以构建列表? - foxdonut

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接