Post view model instance back to several action me

2019-07-01 20:08发布

I have one ViewModel which has 8 properties and 6 of them are complex types. And I must display them in 3 groups and to save all data to database at last. Now, I have created two methods for this purpose, the first will be decorated with HttpGet and the second one with HttpPost. I have already created all these 3 groups in one .cshtml. For the first time, only the first group is visible. And after clicking NEXT button, I will make the second group visible and the first group will be invisible with the help of Javascript/Jquery. And then the third group will be visible. And in this last part submit button must be appeared. After clicking this, I will post whole model back to the action method. But, in this scenario I have two problems:

  • I must validate only visible fields with client side validation
  • If somehow the client side validation passed and the server side is not, then I must find and display not validated part.

So, for solving these problems, I have decided two create four action methods, which will post viewmodel back to other one. For making it clear, I want to show this like that:

  1. CreateViewModel [HttpGet]
  2. GoToSecondPart [HttpPost]
  3. GoToThirdPart [HttpPost]
  4. SaveToDatabase [HttpPost]

1 will return my viewmodel instance to 2, and 2 in his turn will post it to 3, and 3 will post it to 4.

Is it good aproach? If not, what would you recommend me?

2条回答
Emotional °昔
2楼-- · 2019-07-01 20:23

It sounds to me that you are trying to make a wizard. It would be easier to break your pages into partials, using the same view model but displaying only the fields that are required for that page (throw the others into hidden fields to save the data). You could then make AJAX calls back to your controller to render the next / previous pages which will prevent the screen flicker making it look like the page hasn't changed.

查看更多
放我归山
3楼-- · 2019-07-01 20:31

Your current approach means multiple post/redirects and some form of temporary repository or something that mimics viewstate. A better approach would be to do everyting within one form and validate individual controls in each section using Validator.element(element)

In the Next button .click() event

  1. Select all the the controls within the associated <section> - e.g. var controls = $(this).closest('section').find('input, textarea, select');
  2. In an $.each loop, call $('form').validate().element($(this));
  3. Test if the controls in the section are valid with $(this).valid();
  4. If everything is valid, hide the current section and display the next

The final section includes the 'Save'` button which does a normal submit

View

<section>
    <h2>Section 1</h2>
    @Html.LabelFor(m => m.SomeProperty)
    @Html.TextBoxFor(m => m.SomeProperty)
    @Html.ValidationMessageFor(m => m.SomeProperty)
    ....
    <div class="error"></div>
    <button type="button" class="next">Next</button>
</section>
<section>
    <h2>Section 2</h2>
    // Your inputs and validation
    <div class="error"></div>
    <button type="button" class="next">Next</button>
<section>
<section>
    <h2>Section 3</h2>
    // Your inputs and validation
    <div class="error"></div>
    <button type="submit" class="next">Submit</button> // submit button for last section
</section>

css (hide all but the first section)

section:not(:first-of-type) {
    display:none;
}

Script

$('button').click(function () {
  var container = $(this).closest('section');
  var isValid = true;     
  $.each(container.find('input'), function () { // include select, textarea as required
    $('form').validate().element($(this));
    if (!$(this).valid()) {
      isValid = false;
      return false;
    }
  });
  if (isValid) {
    container.next('.section').show().find('input').first().focus();
    container.hide();
  } else {
    container.find('.error').text('please complete');
  }
});

This will address all client side validation without the need for multiple posts/redirects. As for what happens in the rare instance of having to return the view because the model is still invalid (the error message(s) will be generated but could be in a hidden section so not initially visible)

  1. Just let the user step through the 'wizard' again (may be confusing if an error is not visible in the first section)
  2. Use jquery to find the generated error(s), for example $('span.field-validation-error) and the unhide the associated parent section(s)
查看更多
登录 后发表回答