Announcement Announcement Module
Collapse
No announcement yet.
Spring form Tags and Multiple Models Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring form Tags and Multiple Models

    I have a registration page which asks for both Company and User details including password verification.

    In the application I have a separate Company bean and a User bean.

    Using the Spring form tags library it seems I can only create a form in the .jsp file as either

    <form:form commandName="User">

    or

    <form:form commandName="Company">

    So is it true that if I want to use the form tag library I can only have binding to a single domain model (User or Company), or else I need to create a super Bean UserCompany and use this for the domain model ?

    Is there another nice solution for this that includes binding ?

    Thanks for any help.

  • #2
    You have to have a single model attribute per form. So, if your view contains a single form, you will need to have a "wrapper" object to pass to that form as its model. That's perfectly fine to have a UI-specific command object that nests several domain objects.

    However, when appropriate, one may also easily create a single view with multiple forms, where each form would use its own model attribute. For that you can do the following:

    Code:
        <form:form id="form1" modelAttribute="cmdObjectOne">
        ...
        </form:form>
    
       
        <form:form id="form2" modelAttribute="cmdObjectTwo">
        ...
        </form:form>
    Have your controller (request handler methods) properly populate the Model with the instances for all the necessary model attribute objects. For example:

    Code:
    public ModelAndView something(...) {
    
       ModelAndView mv = new ModelAndView("myview");
        ... // do whatever the handler needs to do
       mv.addObject("cmdObjectOne", new CommandObjectOne());
       mv.addObject("cmdObjectTwo", new CommandObjectTwo());
       return mv; // return view with two model attributes for 2 forms
    }
    HTH,
    Constantine

    Originally posted by springflan View Post
    I have a registration page which asks for both Company and User details including password verification.

    In the application I have a separate Company bean and a User bean.

    Using the Spring form tags library it seems I can only create a form in the .jsp file as either

    <form:form commandName="User">

    or

    <form:form commandName="Company">

    So is it true that if I want to use the form tag library I can only have binding to a single domain model (User or Company), or else I need to create a super Bean UserCompany and use this for the domain model ?

    Is there another nice solution for this that includes binding ?

    Thanks for any help.

    Comment


    • #3
      Thanks for the quick reply.

      I have tried the 2 form/view method but the problem is there needs to be 2 "submit" buttons and each one only submits that part of the form to which it belongs and ignores the contents of the other form.

      It seems the "wrapper" approach is the easiest solution, unless I have missed somehing.


      Originally posted by constv View Post
      You have to have a single model attribute per form. So, if your view contains a single form, you will need to have a "wrapper" object to pass to that form as its model. That's perfectly fine to have a UI-specific command object that nests several domain objects.

      However, when appropriate, one may also easily create a single view with multiple forms, where each form would use its own model attribute. For that you can do the following:

      Code:
          <form:form id="form1" modelAttribute="cmdObjectOne">
          ...
          </form:form>
      
         
          <form:form id="form2" modelAttribute="cmdObjectTwo">
          ...
          </form:form>
      Have your controller (request handler methods) properly populate the Model with the instances for all the necessary model attribute objects. For example:

      Code:
      public ModelAndView something(...) {
      
         ModelAndView mv = new ModelAndView("myview");
          ... // do whatever the handler needs to do
         mv.addObject("cmdObjectOne", new CommandObjectOne());
         mv.addObject("cmdObjectTwo", new CommandObjectTwo());
         return mv; // return view with two model attributes for 2 forms
      }
      HTH,
      Constantine

      Comment


      • #4
        I have tried the 2 form/view method but the problem is there needs to be 2 "submit" buttons and each one only submits that part of the form to which it belongs and ignores the contents of the other form.

        It seems the "wrapper" approach is the easiest solution, unless I have missed somehing.
        That's true, the multi-form view is only appropriate and desirable when you indeed want to be able to separately submit different subsets of the page data. For what you are doing, it is necessary to create a single form-backing bean. Note that it is just a presentation-tier-specific Spring MVC "command" object that will nest your [re-usable domain] objects without itself being part of the domain model. That is perfectly fine, and it's just a matter of convenience, not much overhead here. Just make sure you keep such classes (UI command objects and domain objects) in separate modules.

        Comment


        • #5
          Problem with Wrapper

          Hi springflan,

          When we use the wrapper containing Company and User beans in a single bean then the form will work fine and easily you can match with the bean properties BUT the problem here is you might find difficulty in using spring validator. This might not able to recognise the properties while binding the errors to the wrapper class.

          If you have a look to one of my post recently [http://forum.springsource.org/showthread.php?t=82203] i was facing the same issue. So then i created a wrapper class then it worked fine later i was not able to validate it using spring validator. I have attached the sample code for quick solution but still i dont find any solution for it. Suppose if i want to add a delete button for deleting an account i may face a problem again.

          So before proceeding further think all the scenarios and proceed.

          Suggestions are welcome.

          Regards
          Rauf

          Comment


          • #6
            Just to explain what I did and it seems to work fine. Comments welcome.

            - created the wrapper bean UserCompany for User and Company.

            - UserCompany has 2 methods, getUser, getCompany to return the component User and Company beans

            - created User validator, Company validator and UserCompanyValidator all implementing the Validator interface.

            - UserCompanyValidator is essentially a wrapper validator which just calls the UserValidator and CompanyValidator in its validate method as follows:

            - errors from both models are accumulated into e

            public void validate(Object object, Errors e) {

            UserCompany userCompany = (UserCompany)object;

            // Validate the company
            Company company = userCompany.getCompany();
            CompanyValidator companyValidator = new CompanyValidator();

            companyValidator.validate(company, e);

            // Validate the user
            User user = userCompany.getLocation();
            UserValidator userValidator = new UserValidator();

            userValidator.validate(user, e);
            }




            Originally posted by Rauf Khan View Post
            Hi springflan,

            When we use the wrapper containing Company and User beans in a single bean then the form will work fine and easily you can match with the bean properties BUT the problem here is you might find difficulty in using spring validator. This might not able to recognise the properties while binding the errors to the wrapper class.

            If you have a look to one of my post recently [http://forum.springsource.org/showthread.php?t=82203] i was facing the same issue. So then i created a wrapper class then it worked fine later i was not able to validate it using spring validator. I have attached the sample code for quick solution but still i dont find any solution for it. Suppose if i want to add a delete button for deleting an account i may face a problem again.

            So before proceeding further think all the scenarios and proceed.

            Suggestions are welcome.

            Regards
            Rauf

            Comment


            • #7
              Originally posted by springflan View Post
              - created User validator, Company validator and UserCompanyValidator all implementing the Validator interface.

              - UserCompanyValidator is essentially a wrapper validator which just calls the UserValidator and CompanyValidator in its validate method as follows:

              - errors from both models are accumulated into e

              public void validate(Object object, Errors e) {

              UserCompany userCompany = (UserCompany)object;

              // Validate the company
              Company company = userCompany.getCompany();
              CompanyValidator companyValidator = new CompanyValidator();

              companyValidator.validate(company, e);

              // Validate the user
              User user = userCompany.getLocation();
              UserValidator userValidator = new UserValidator();

              userValidator.validate(user, e);
              }
              I'm just observing this thread and don't have a real need to do this myself yet but think I might in the future.

              I'm wondering how the field errors work when using the nested approach.

              Imagine User had a first name which must have some content. The UserValidator checks the User object and populates Errors object with "firstName". Great.

              The problem I envisage is when your UserCompanyValidator object delegates to UserValidator which will generate an error called "firstName". However, for a UserCompany, the correct field name is "user.firstName" because of the nesting. The error will therefore not appear on the web page. Have you checked this out?

              PUK
              Last edited by PUK_999; Dec 29th, 2009, 05:36 AM. Reason: Changed "method" to "approach" to avoid confusion.

              Comment


              • #8
                Originally posted by PUK_999 View Post
                The problem I envisage is when your UserCompanyValidator object delegates to UserValidator which will generate an error called "firstName". However, for a UserCompany, the correct field name is "user.firstName" because of the nesting. The error will therefore not appear on the web page. Have you checked this out?
                PUK
                To avoid this problem, invocations of the wrapped validators should be surrounded by Errors.pushNestedPath/Errors.popNestedPath.

                Comment


                • #9
                  To respond to PUK:

                  When I step through the errors generation and handling the error codes generated are the following

                  company.name.empty.userCompany.name, company.name.empty.name, company.name.empty.java.lang.String, company.name.empty

                  (similar for the User)

                  So the errors are prefixed with the base bean and they show up the errors correctly on the Web page both for the User and the Company fields.

                  I don't know the details of how or why but I didn't need to do as suggested by axtavt.

                  Comment

                  Working...
                  X