Eric Huang
Eric Huang

Reputation: 1264

Spring-MVC @modelAttribute how to send list of object to view in separate form and update one object at a time

I have a controller that goes to the DB and get a list of books. I like to use @modelAttribute to display individual books in separate form so I can do quick edits on each item.

Controller

@RequestMapping("/")
public String pagIndex(Model model){
    System.out.println("loading index page");
    // Get list of books
    List<Book> books = bookDao.getBookList();
    // List of object to Model
    model.addAttribute("books", books);

    return "index";
}

View

<h3>Book Inventory</h3>
<table>
    <tr>
        <td>ID</td>
        <td>Book Name</td>
        <td>ISPN</td>
        <td>Price</td>
        <td></br><td>
        <td>Object</td>

    </tr>
    <!-- Each book in separate form for easy update -->
    <c:forEach var="book" items="${books}">
    <tr>
        <sf:form class="editeForm" action="${pageContext.request.contextPath}/edititem" modelAttribute="book"  method="POST">

            <td>${book.id} <input type="hidden" path="id" name="id"></td>
            <td><sf:input type="text" path="name" name="name" /></td>
            <td><sf:input type="text" path="ispn" name="ispn" /></td>
            <td><sf:input type="text" path="price" name="price" /></td>
            <td></br><td>
            <td>${book}</td>
            <td><input type="submit" value="save edite"><input type="submit" name="delete" value="delete"></td>

        </sf:form>
    </tr>
    </c:forEach>
</table>

When i set modelAttribute="book" stack trace is

Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'book' available as request attribute
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:144)

modelAttribute="${book}" stack trace is

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'Book bean [id=1, name=Java: A Beginner's Guide, ispn=978-0071809252, price=18' available as request attribute

Update: If I use plain JSTL it works but anyway to use modelAttriburte?

<h3>Book Inventory</h3>
<table>
    <tr>
        <td>ID</td>
        <td>Book Name</td>
        <td>ISPN</td>
        <td>Price</td>
        <td></br><td>
        <td>Object</td>

    </tr>
    <!-- Each book in separate form for easy update -->
    <c:forEach var="book" items="${books}">
    <tr>
        <form class="editeForm" action="${pageContext.request.contextPath}/edititem"  method="POST">

            <td>${book.id} <input type="hidden" name="id" value="${book.id}"/></td>
            <td><input type="text" name="name" value="${book.name} /></td>
            <td><input type="text" name="ispn" value="${book.ispn} /></td>
            <td><input type="text" name="price" value="${book.price} /></td>
            <td></br><td>
            <td>${book}</td>
            <td><input type="submit" value="save edite"><input type="submit" name="delete" value="delete"></td>

        </form>
    </tr>
    </c:forEach>
</table>

Upvotes: 0

Views: 2755

Answers (2)

Serge Ballesta
Serge Ballesta

Reputation: 148965

When you write:

<c:forEach var="book" items="${books}">

the book variable is indeed created for each iteration, but it is only a page scoped variable and not a request attribute. And as the error says, Spring modelAttribute is expected to be a request attribute. As I know no trivial way to dynamically make the book variable be a true spring model attribute, my advice is to stick with plain JSTL.

As the JSTLView by default only puts the model attributes as request attributes with their name, you could use a little scriptlet to try to cheat spring:

<c:forEach var="book" items="${books}">
    <%
        Object obj = pageContext.findAttribute("book");
        request.setAttribute("book", obj);
    %>
    ...

But I really urge you not to do that, because it relies on Spring implementation details that can change even in a minor release

Upvotes: 1

0gam
0gam

Reputation: 1423

You use <c:forEach var="result" items="${books}" varStatus="status"> and ${result.id} . you check in controller, by any chance? your books.

Upvotes: 0

Related Questions