11

メールのリストPerson含むモデル属性があります。

電子メールの HTML リストから要素を削除する JavaScript コードをいくつか作成しました。これは純粋な JavaScript クライアント側コードであり、AJAX 呼び出しではありません。

送信後、HTML で削除されたメールも含めて、対応するメソッドですべてのメールを取得する理由がわかりません。@Controller

誰でも説明できますか?


JSP

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <link rel="stylesheet" href="<c:url value="/styles/resume.css"/>" type="text/css"></link>
    <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"></link>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
    <script src="/resume/js/jquery.editable-1.0.1.js"></script>
    <title>Resumes manager</title>

    <script>
    $(document).ready(function() {
        $('.trash').click(function() {
            $(this.parentNode).remove();
        });

    });

    </script>
</head>

<body>
    <h1>Personal data</h1>
    <form:form modelAttribute="person" action="/resume/person/edit/save" id="personForm" method="post" >
        <table>
            <tr>
                <td>Email addresses:</td>
                <td colspan="4">
                    <ol id="emails">
                        <c:forEach items="${person.emails}" varStatus="status">
                            <li><form:hidden path="emails[${status.index}].order" class="emailsDisplayOrder"></form:hidden><form:input path="emails[${status.index}].label"></form:input><form:input type="email" path="emails[${status.index}].value"></form:input><input type="image" src="/resume/images/trash.png" class="trash" value="${status.index}"></input></li>
                        </c:forEach>
                    </ol>
                </td>
            </tr>
        </table>
    </form:form>
</body>

</html>

コントローラ

@Controller
@SessionAttributes(types={Person.class}, value={"person"})
public class PersonController {

    private final static String PERSON_VIEW_NAME = "person-form";

    private ResumeManager resumeManager;

    @Autowired()
    public PersonController(ResumeManager resume) {
        this.resumeManager = resume;
    }

    @InitBinder
    public void initBinder(WebDataBinder dataBinder) {
        dataBinder.setDisallowedFields("id");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }

    @RequestMapping(value="/person/edit/save")
    public String save(@ModelAttribute(value="person") Person p, BindingResult result, SessionStatus status) {
        new PersonValidator().validate(p, result);
        Collections.sort(p.getEmails()); //this collection still contains client-side dropped objects

        this.resumeManager.savePerson(p);

        return PERSON_VIEW_NAME;
    }
}
4

2 に答える 2

8

説明

でページをロードする場合<form:form modelAttribute="person" ...>、次の 2 つのケースがあります。

  • ケース 1 :person存在しない場合は、空を作成しますPerson
  • ケース 2 :person既に存在する場合は、それを使用します

どの場合でも、ページが読み込まれると、既存のperson.
フォームを送信すると、Spring MVCは送信された情報のみで既存の thisを更新します。person

したがって、ケース 1 で電子メール 1、2、3、および 4 を送信すると、Spring MVC は空の に 4 つの電子メールを追加しますperson。この場合は問題ありません。

ただし、ケース 2 (たとえば、既存personのセッションを編集する場合) で、電子メール 1 と 2 を送信しても、その人物が既に 4 つの電子メールを持っている場合、Spring MVC は電子メール 1 と 2 を置き換えるだけです。電子メール 3 と 4 はまだ存在します。


可能な解決策

おそらく最良のものではありませんが、うまくいくはずです。

クラスにremoveブール値を追加します。Email

...
public class Email {

    ...

    private boolean remove; // Set this flag to true to indicate that 
                            // you want to remove the person.

    ...

}

コントローラーのsaveメソッドで、true に設定されているメールを削除removeします。

最後に、JSP に次の非表示フィールドを追加します。

<form:hidden path="emails[${status.index}].remove" />

また、ユーザーがクリックしてメールを削除したときに、入力値を true に設定するように Javascript に指示します。

于 2012-10-12T16:44:35.177 に答える
0

Jerome Dalbert の代替ソリューション

ジェロームのソリューションはうまくいくはずですが(明確な回答とソリューションに感謝します)、ビジネスモデルを変更したくありませんでした。
だから私が見つけた方法は次のとおりです.Javaスクリプトを使用して削除するHTML要素をマークし、フォーム送信時にajax呼び出しを使用して実際に削除します(最初は、ユーザーが送信するまでモデルを変更しないようにajaxを避けましたが、このソリューションはその要件を保持します)。

JSP:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <link rel="stylesheet" href="<c:url value="/styles/resume.css"/>" type="text/css"></link>
    <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"></link>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
    <script src="/resume/js/jquery.editable-1.0.1.js"></script>
    <title>Resumes manager</title>

    <script>
        $('.sortable').sortable({
            update: function(event,ui) {
                var liElements = this.getElementsByTagName('li');
                $(liElements).each(function(i, liElement) {
                    var orderElements = liElement.getElementsByClassName('order');
                    $(orderElements).each(function (j, orderElement) {
                        orderElement.value = i;
                    });
                });
            }
        });

        $('.trashable').click(function() {
            $(this.parentNode.childNodes).each(function(index, element) {
                if(element.src.match(/trash.png/) != null) {
                    element.src = '/resume/images/back.png';
                    this.parentNode.className = 'trashed';
                } else if(element.src.match(/back.png/) != null) {
                    element.src = '/resume/images/trash.png';
                    this.parentNode.className = '';
                } else {
                    element.disabled = !element.disabled;
                }
            });
        });

        function trash(element) {
            var sfx = element.alt;
            var lnk = ('/resume/person/edit/').concat(sfx);
            $.ajax({
                url: lnk
            });
        }

        $('#personForm').submit(function() {
            var trashed = $(this).find('.trashed');
            $(trashed).each(function(index, element) {
                var img = $(element).find('.trashable');
                var tmp = $(img)[0];
                trash(tmp);
            });
        });
    });

    </script>
</head>

<body>
    <h1>Personal data</h1>
    <form:form modelAttribute="person" action="/resume/person/edit/save" id="personForm" method="post" >
        <table>
            <tr>
                <td>Email addresses:</td>
                <td colspan="4">
                    <ol class="sortable">
                        <c:forEach items="${person.emails}" varStatus="status">
                            <li><form:hidden path="emails[${status.index}].order" class="order"></form:hidden><form:input path="emails[${status.index}].label"></form:input><form:input type="email" path="emails[${status.index}].value"></form:input><img src="/resume/images/trash.png" class="trashable" alt="dropEmail/${person.emails[status.index].id}"></img></li>
                        </c:forEach>
                    </ol>
                </td>
            </tr>
            <tr><td colspan="5"><form:button name="save" value="${person.id}">${person.id == 0 ? 'save' : 'update'}</form:button></td></tr>
        </table>
    </form:form>
</body>

</html> 

コントローラ:

@Controller
@SessionAttributes(types={Person.class}, value={"person"})
public class PersonController {

    private final static String PERSON_VIEW_NAME = "person-form";

    private ResumeManager resumeManager;

    @Autowired()
    public PersonController(ResumeManager resume) {
        this.resumeManager = resume;
    }

    @InitBinder
    public void initBinder(WebDataBinder dataBinder) {
        dataBinder.setDisallowedFields("id");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        dataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }

    @RequestMapping(value="/person/edit/{id}")
    public String edit(@PathVariable("id") long personId, Model model) {
        Person p = this.resumeManager.getPersonById(personId);

        if(p != null) {
            model.addAttribute("person", p);

            return PERSON_VIEW_NAME;

        } else {
            return "redirect:/";
        }
    }

    @RequestMapping(value="/person/edit/save")
    public String save(@ModelAttribute(value="person") Person p, BindingResult result, SessionStatus status) {
        new PersonValidator().validate(p, result);
        Collections.sort(p.getEmails());

        this.resumeManager.savePerson(p);

        return PERSON_VIEW_NAME;
    }

    @RequestMapping(value="/person/edit/dropEmail/{id}")
    @ResponseBody
    public void dropEmail(@ModelAttribute(value="person") Person p, @PathVariable("id") long id) {
        int i = 0;
        for(Email e : p.getEmails()) {
            if(e.getId() == id) {
                p.getEmails().remove(i);
                break;
            }
            i++;
        }
    }
}
于 2012-10-13T10:02:15.040 に答える