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

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

问题描述

我的问题是:我想创建一个 grails 域实例,定义它拥有的另一个域的许多"实例.我在 Google 代码项目 但下面应该能说明问题.

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

如果你对这两个控制器使用这个模型和 def scaffold 那么你最终会得到这样一个不起作用的表单;

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

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

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.

如果我使用 HTML Select 则可以正常工作!如下所示制作创建页面;

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>   

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

<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

推荐答案

将你的 create.gsp <g:checkbox...> 代码替换为:

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

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

然后在控制器的 save 操作中,将 def VolunteerInstance = new Volunteer(params) 替换为:

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 问题 - 在 create.gsp 中使用 CheckBoxes 而不是 HTML Select的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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