0

I'm making the transition from webforms to MVC (I know, 3 years late) and I "get it" for the most part, but there's a few things I'd like advice and clarification on:

First off, what happens if you want to dynamically add inputs to a view? for example, in an old webform for generating invoices I had a button with a server-side click event handler that added an extra 5 invoice item rows. The stateful nature of webforms meant the server handled the POST event "safely" without altering the rest of the page.

In MVC I can't think how I'd do this without using client-side scripting (not a showstopper, but I would like to support clients that don't have scripting enabled).

The second problem relates to the invoices example. If my Model has a List, how should I be generating inputs for it?

I know data binding is a possible solution, but I dint like surrendering control.

Finally, back to the "stateful pages" concept - say I've got a Dashboard page that has a calendar on it (I wrote my own calendar Control class, the control itself is stateless, but can use the webform viewstate to store paging information) - how could a user page through the calendar months? Obviously POST is inappropriate, so it would have to be with GET with a querystring parameter - how can I do this in MVC? (don't say AJAX).

Thanks!

3 Answers 3

2

In MVC you design your actions to accommodate your needs. For example, if you wanted to be able to add 5 rows to an invoice NOT using client-side scripting, you'd probably have your GET action for the invoice generation take a nullable int parameter for the number of rows. Store the current number of rows in the view model for the page and generate a link on the page to your GET action that has the parameter value set to 5 more than the current value. The user clicks the link and the GET view generates the page with the requested number of rows.

Controller

 [HttpGet]
 public ActionResult Invoice( int? rows )
 {
      rows = rows ?? 5; // probably you'd pull the default from a configuration
      ...

      viewModel.CurrentRows = rows;
      return View( viewModel );
 }

View

 @Html.ActionLink( "Add 5 Lines", "invoice", new { rows = Model.CurrentRows + 5 }, new { @class = "add-rows" } )

You would probably also add some script to the page that intercepts the click handler and does the same thing via the script that your action would do so that in the general case the user doesn't have to do a round trip to the server.

 <script type="text/javascript">
      $(function() {
          $('.add-rows').click( function() {
                ...add additional inputs to the invoice...
                return false; // abort the request
          });
      });
 </script>

Likewise for your calendar. The general idea is you put enough information in your view model to generate all the actions that you want to perform from your view. Construct the links or forms (yes you can have multiple forms!) in your view to do the action. Use parameters to communicate to the controller/action what needs to be done. In the rare case where you need to retain state between actions, say when performing a wizard that takes multiple actions, you can store the information in the session or use TempData (which uses the session).

For things like a calendar you'd need the current date and the current view type (month/day/year). From that you can construct an action that takes you to the next month/day/year. For a paged list you need the current page, the current sort column and direction, the number of items per page, and the number of pages. Using this information you can construct your paging links that call back to actions expecting those parameters which simply do the right thing for the parameters with which they are called.

Lastly, don't fear AJAX, embrace it. It's not always appropriate (you can't upload files with it, for example), but your users will appreciate an AJAX-enabled interface.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, but I have a few questions: if a user enters data into the form, then decides to add more rows then they would lose what the typed, is the only solution there to use a client script? Also, how is the content of the newly-added rows added to my model object during a POST so my controller can read it?
@David - there's a fundamental design decision here. I would probably go with a simple solution that presumes the user has JS enabled and do it the way I've described. A user without JS enabled would have a degraded experience, but they could get the enhanced experience by simply turning on JS, so that's really their choice. Otherwise, you have a more complicated solution that takes your POST action responding to a "Add 5 Rows" submit button click - give it a name and it will post back as a parameter you can detect - and have it regenerate the view with the data and the extra rows.
0

In MVC you can store application state in various ways. In your controller you have direct access to the Session object and you can also store state to the database.

Comments

0

your view can contain basic control flow logic, so, if your model has a list you can iterate over it in the view and, for example, render an input control for each item in the list. you could also set a variable in a model to be the maximum number of rows on the viewpage and then render a row in a table for the number specified by the model.

paging is basically the same thing. you can create a partial view (user control in the webform world) that shows page numbers as links, where each link calls an action that fetches the data for that page of results.

i'm not sure what your beef is with ajax or javascript

4 Comments

If a user does a POST on a page that had inputs generated by an iteration, how does the controller read back that information? How can I perform validation too? Ta!
model validation is built into the framework: asp.net/mvc/mvc3#BM_Model_Validation_Improvements. the controller accepts a list of items as one of it's parameters, and the mvc model binder is responsible for ensuring the posted data is converted to the appropriate list type and passed into the controller
I know that, but I mean how can I get data and validate it in the context of a dynamically added input?
you add validation to a model, and then your page will post a list of models to your controller. the validation will fire on the list of models regardless of the number that is posted. you can also implement your own custom validation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.