マイペースなRailsおじさん

Ruby、Ruby on Rails、オブジェクト指向設計を主なテーマとして扱います。だんだん大きくなっていくRuby on Rails製プロダクトのメンテナンス性を損なわない方法を考えたり考えなかったりしている人のブログです。

Spring + JSP + JQueryでポチポチしてフォームを増やしたい。

ポチポチしたい

フォームをネストして、サブフォームをいっぱい持つParentForm

package myspring.web;

import java.io.Serializable;
import java.util.List;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class ParentForm implements Serializable{
    private static final long serialVersionUID = 1L;
    
    private List<ChildForm> children;
    
    @NotNull
    @Size(min = 1, max = 20)
    private String name;    
    /**
     * 
     */
    public ParentForm() {
	super();
    }
    /**
     * @return the children
     */
    public List<ChildForm> getChildren() {
        return this.children;
    }
    /**
     * @param children the children to set
     */
    public void setChildren(List<ChildForm> children) {
        this.children = children;
    }
    /**
     * @return the name
     */
    public String getName() {
        return this.name;
    }
    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
}

いっぱい持たれるChildForm

package myspring.web;

public class ChildForm {
    private String name;
    private String group;
    /**
     * 
     */
    public ChildForm() {
	super();
    }
    /**
     * @return the name
     */
    public String getName() {
        return this.name;
    }
    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * @return the group
     */
    public String getGroup() {
        return this.group;
    }
    /**
     * @param group the group to set
     */
    public void setGroup(String group) {
        this.group = group;
    }
}

Controller

package myspring.web;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class WelcomeController {
    @RequestMapping("/")
    public String fuck(Model model) {
	return "welcome";
    }
    
    @RequestMapping("/me")
    public String me(ParentForm form, Model model) {
	form.setChildren(Arrays.asList(new ChildForm(), new ChildForm()));
	model.addAttribute("form", form);
	return "fuckYou";
    }
    
    @RequestMapping("/new")
    public String rec(@Valid ParentForm form, BindingResult result, Model model) {
	if (form.getChildren() != null) {
	form.getChildren().stream()
		.filter(Objects::nonNull)
		.forEach(child -> System.out.println("forEach" + child.getName()));
	
	List<ChildForm> childforms = form.getChildren().stream()
		.filter(Objects::nonNull)
		.filter(child -> child.getName() != null)
		.collect(Collectors.toList());
	
	form.setChildren(childforms);
	}
	model.addAttribute("form", form);
	if (result.hasErrors()) {
	    return "fuckYou";
	}
	return "fuckMe";
    }    
}

JSPは、JQueryを使ったけど、たいしたことしてないので使わないほうがいいかもしれない。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Sub Form Sample</title>
<script src="/webjars/jquery/2.2.4/jquery.min.js"></script>
</head>
<body>
<c:set var="count" value="0"/>
<h2>Sub Form Sample</h2>
  <form:form modelAttribute="form" action="/new">
    <table>
      <tr>
        <td colspan="4">
          <button type="button" id="add">Add</button>          
        </td>
      </tr>
      <c:forEach items="${form.children}" varStatus="rowS" var="item">
        <tr id="subform${rowS.index}">
          <td>Name</td>
          <td><form:input path="children[${rowS.index}].name" /></td>
          <td>Group</td>
          <td><form:input path="children[${rowS.index}].group" /></td>
          <td><button type="button" class="remove" onclick="removeForm(${rowS.index})">Remove</button></td>
        </tr>
        <c:set var="count" value="${rowS.index + 1}" />
      </c:forEach>
      <tr id="subformanker"><td></td></tr>
      <tr>
        <td colspan="4"><input type="submit" value="Save Changes" /></td>
      </tr>
    </table>
  </form:form>

  <script>
      var count = ${count};
      function removeForm(index) {
        $("#subform" + index).remove();
        console.log(count);
      }
      $(document).ready(function () {
        $("#add").click(function (event) {
          $('<tr id=subform' + count + '>').append("<td>Name</td>")
                .append('<td><input id="children' + count + '.name" name="children[' + count + '].name" type="text" value=""/></td>')
                .append('<td>Group</td>')
                .append('<td><input id="children' + count + '.group" name="children[' + count + '].group" type="text" value=""/></td>')
                .append('<td><button type="button" class="remove" onClick="removeForm(' + count + ')">Remove</button></td>')
                .insertBefore("#subformanker");        
          console.log(count);
          count += 1;
        });      
      });

    </script>
</body>
</html>