Grails - 简单hasMany问题 - 使用CheckBox而不是HTML在create.gsp中选择 [英] Grails - Simple hasMany Problem - Using CheckBoxes rather than HTML Select in create.gsp

查看:147
本文介绍了Grails - 简单hasMany问题 - 使用CheckBox而不是HTML在create.gsp中选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是:我想创建一个Grails域实例,定义它拥有的另一个域的'Many'实例。我有 $ b

 %3Fstate%3Dclosedrel =noreferrer> Google Code Project ,但以下内容应说明问题所在。 class Person {
String name
static hasMany [技能:技能]

静态约束= {
id(visible:false)
技能(可空: false,blank:false)
}
}

class Skill {
字符串名称
字符串描述

静态约束= {
id(可见:false)
名称(可空:false,空:false)
描述(可空:false,空白:false)
}
}

如果您使用此模型并且 def scaffold 这两个控制器,然后你最终得到这样的表单不起作用;





My ow ñ试图让这个工作枚举技能作为复选框,看起来像这样;





但是当我保存志愿者的时候,这些技能都是空的!

< img src =https://imgur.com/2gW39.pngalt =无法保存技能>



这是我的保存方法的代码;

  def save = {
log.infoSaving:+ params.toString()
def技能= params.skills
log.infoSkills:+ skills
def volunteerInstance = new Volunteer(params)
log.info volunteerInstance
if(volunteerInstance.save(flush:true )){
flash.message =$ {message(code:'default.created.message',args:[message(code:'volunteer.label',default:'Volunteer'),volunteerInstance.id] )}
redirect(action:show,id:volunteerInstance.id)
log.info volunteerInstance
}
else {
渲染(view:create,model:[volunteerInstance:volunteerInstance])
}
}

这是我的日志输出(我有自定义的toString()方法);

  2010-05-10 21 :06:41,494 [http-8080-3] INFO bumbumtrain.VolunteerController  -  Saving:[skills:[1,2],name:Ian,_skills:[, ],创建:创建,动作:保存,控制器:志愿者] 

2010-05-10 21:06:41,495 [http-8080- 3] INFO bumbumtrain.VolunteerController - 技能:[1,2]

2010-05-10 21:06:41,508 [http-8080-3] INFO bumbumtrain.VolunteerController - Volunteer [id:null |名称:Ian |技能[Skill [id:1 |名称:木匠],技能[id:2 |请注意,在最后的日志行中,正确的技能已经被提取出来了。并且是对象实例的一部分。当志愿者被保存时,'技能'被忽略,并且没有被提交到数据库,尽管内存版本显然确实具有这些项目。在施工时是否无法通过技能?这一定有办法吗?我需要一个表单来允许一个人注册,但我想规范化数据,以便我可以在以后添加更多技能。



如果您认为这应该'只是工作',那么一个工作示例的链接就会很好。



如果我使用HTML Select,那么它可以正常工作!如下所示制作Create页面;

 < tr class =prop> 
< td valign =topclass =name>
< label for =skills>< g:message code =volunteer.skills.labeldefault =技能/>< / label>
< / td>
< td valign =topclass =value $ {hasErrors(bean:volunteerInstance,field:'skills','errors')}>
< / td>
< / tr>

但我需要它来处理像这样的复选框;

 < tr class =prop> 
< td valign =topclass =name>
< label for =skills>< g:message code =volunteer.skills.labeldefault =技能/>< / label>
< / td>
< td valign =topclass =value $ {hasErrors(bean:volunteerInstance,field:'skills','errors')}>
< label for =$ {skillInstance?.name}>< g:message code =$ {skillInstance?.name} .labeldefault =$ {skillInstance?.name}/ >< /标签>
< / g:每个>
< / td>
< / tr>

日志输出完全相同!志愿者实例是通过技能变量中正确引用的技能创建的。保存时,后者将失败,并在此问题的顶部显示空引用异常。



希望这是有道理的,谢谢!



Gav

解决方案

替换您的 create.gsp < g:checkbox ...> code by:

    

然后在控制器的 save 动作中,替换 def volunteerInstance = new Volunteer(params)通过:

  def志愿者实例=新志愿者(名称:params.name)
params.each {
if(it.key.startsWith(skill_))
volunteerInstance.skills<< Skill.get((it.key - skill_)为整数)
}

应该管用。 (代码未经测试)


My problem is this: I want to create a grails domain instance, defining the 'Many' instances of another domain that it has. I have the actual source in a Google Code Project but the following should illustrate the problem.

class Person {
  String name
  static hasMany[skills:Skill]

  static constraints = {
   id (visible:false)   
   skills (nullable:false, blank:false)
  }
}

class Skill {
  String name
  String description

  static constraints = {
   id (visible:false)   
   name (nullable:false, blank:false)
   description (nullable:false, blank:false)
  }
}

If you use this model and def scaffold for the two Controllers then you end up with a form like this that doesn't work;

My own attempt to get this to work enumerates the Skills as checkboxes and looks like this;

But when I save the Volunteer the skills are null!

This is the code for my save method;

def save = {
    log.info "Saving: " + params.toString()
    def skills = params.skills
    log.info "Skills: " + skills 
    def volunteerInstance = new Volunteer(params)
    log.info volunteerInstance
    if (volunteerInstance.save(flush: true)) {
        flash.message = "${message(code: 'default.created.message', args: [message(code: 'volunteer.label', default: 'Volunteer'), volunteerInstance.id])}"
        redirect(action: "show", id: volunteerInstance.id)
        log.info volunteerInstance
    }
    else {
        render(view: "create", model: [volunteerInstance: volunteerInstance])
    }
}

This is my log output (I have custom toString() methods);

2010-05-10 21:06:41,494 [http-8080-3] INFO  bumbumtrain.VolunteerController  - Saving: ["skills":["1", "2"], "name":"Ian", "_skills":["", ""], "create":"Create", "action":"save", "controller":"volunteer"]

2010-05-10 21:06:41,495 [http-8080-3] INFO  bumbumtrain.VolunteerController  - Skills: [1, 2]

2010-05-10 21:06:41,508 [http-8080-3] INFO  bumbumtrain.VolunteerController  - Volunteer[ id: null | Name: Ian | Skills [Skill[ id: 1 | Name: Carpenter ] , Skill[ id: 2 | Name: Sound Engineer ] ]] 

Note that in the final log line the right Skills have been picked up and are part of the object instance. When the volunteer is saved the 'Skills' are ignored and not commited to the database despite the in memory version created clearly does have the items. Is it not possible to pass the Skills at construction time? There must be a way round this? I need a single form to allow a person to register but I want to normalise the data so that I can add more skills at a later time.

If you think this should 'just work' then a link to a working example would be great.

If I use the HTML Select then it works fine! Such as the following to make the Create page;

<tr class="prop">
<td valign="top" class="name">
  <label for="skills"><g:message code="volunteer.skills.label" default="Skills" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: volunteerInstance, field: 'skills', 'errors')}">
    <g:select name="skills" from="${uk.co.bumbumtrain.Skill.list()}" multiple="yes" optionKey="id" size="5" value="${volunteerInstance?.skills}" />
</td>
</tr>   

But I need it to work with checkboxes like this;

<tr class="prop">
<td valign="top" class="name">
  <label for="skills"><g:message code="volunteer.skills.label" default="Skills" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: volunteerInstance, field: 'skills', 'errors')}">
    <g:each in="${skillInstanceList}" status="i" var="skillInstance">   
      <label for="${skillInstance?.name}"><g:message code="${skillInstance?.name}.label" default="${skillInstance?.name}" /></label>
                                      <g:checkBox name="skills" value="${skillInstance?.id.toString()}"/>
    </g:each>
</td>
</tr> 

The log output is exactly the same! With both style of form the Volunteer instance is created with the Skills correctly referenced in the 'Skills' variable. When saving, the latter fails with a null reference exception as shown at the top of this question.

Hope this makes sense, thanks in advance!

Gav

解决方案

Replace your create.gsp <g:checkbox...> code by:

<g:checkBox name="skill_${skillInstance.id}"/>

Then inside the save action of your controller, replace def volunteerInstance = new Volunteer(params) by :

def volunteerInstance = new Volunteer(name: params.name)
params.each {
  if (it.key.startsWith("skill_"))
    volunteerInstance.skills << Skill.get((it.key - "skill_") as Integer)
}

Should work. (code not tested)

这篇关于Grails - 简单hasMany问题 - 使用CheckBox而不是HTML在create.gsp中选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆