tags:

views:

481

answers:

1

I have an asp.net MVC website. One of the pages allows the user to dynamically add drop down lists to the page, i.e. the user enters 5, this posts back to the server, where in the view I create 5 drop down lists.

What I then want to be able todo is on every post back send all the values of the drop down lists back to the controller, maintaing their position in the array. What I'm finding is that only the changed values are being posted back and I am unable to determine which value changed

?? What, you may ask. Here's an example:

  1. The page allows the user to enter a specification of their house. First they select from a drop down list, drpRooms, the number of rooms in their house (lets say the users enters 5).

  2. This posts back to server and the view is rendered back with 5 additional drop down lists, drpRoom0, drpRoom1, drpRoom2 ... drpRoom4, each drop down lists allow them to select the number of items of furiture in that room, a number between 1 and 10.

  3. The user selects the following values for each drop down

    drpRoom0: 2
    drpRoom1: 4
    drpRoom2: 1
    drpRoom3: 8
    drpRoom4: 9

  4. When the user clicks "Continue" and posts the form back, I get the values in the controller as an array, i.e.. an Array of type int : int[] with values {2, 4, 1, 8, 9}. Upto here I'm okay, I can get the drop down lists posted back as an array of int (I do this by using the same name for each drop down list, but unique ID's)

  5. This will do some processing and so forth. The view gets rendered back to the user and they can change a value, say they change the value of drpRoom3 to value 2, when the user clicks continue, all I get back at the server is an array with 1 value at index 0. Thus I'm unable to determine which drop down list was changed.

I know I can do this with Json, however I'm looking for Javascript independant way in which todo this

+2  A: 

You could use the MVC SelectList object in order to generate your DropDownList controls, and use the Model/ViewModel pattern in order to persist the changes in your system.

First, create the ViewModel class that will used to pass the data to the view:

public class RoomDetailsViewModel
{
    private int _numberOfRooms;
    public int NumberOfRooms
    {
        get { return _numberOfRooms; }
        set
        {
            _numberOfRooms = value;

            RoomDetails = new List<SelectList>(_numberOfRooms);
            for(int i = 0; i < _numberOfRooms; i++)
                RoomDetails.Add(new SelectList(AllowedRoomValues));
        }
    }
    public List<SelectList> RoomDetails { get; set; }

    public RoomDetailsViewModel(RoomDetailsModel model)
    {
        // Get useful info from dataModel
        NumberOfRooms = model.NumberOfRooms;
    }

    public static int[] AllowedRoomValues = new [] {0, 1, 2, 3, 4, 5, 6,7,8,9,10};
}

Note the use of a List of SelectList. Those will be used to generate the DropDownList you need. You can limit the options of your SelectList by providing a list of values (see AllowedRoomValues).

Next, in the Edit view, use the Html helper in order to generate the drop down lists:

<% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="NumberOfRooms">NumberOfRooms:</label>
            <%= Html.TextBox("NumberOfRooms", Model.NumberOfRooms) %>
            <%= Html.ValidationMessage("NumberOfRooms", "*") %>
        </p>

        <% for(int i = 0; i < Model.NumberOfRooms; i++)
           { %>
                <%= Html.DropDownList("drpRoom" + i,Model.RoomDetails[i]) %>
        <% } %>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>

<% } %>

As you can see you have to make sure the RoomDetails property is never null or you will throw a NullRef exception. Best way to do this is via the constructor and setters and I did in the ViewModel.

Finally, you need to update your model in the POST Edit action of your controller:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection collection)
{
    // Grab the actual data model from your ORM repository of choice here
    RoomDetailsModel dataModel = roomDetailRepository.GetItem(r => r.HouseID == id);

    try
    {
        // Updating the model/
        for (int i = 0; i < model.NumberOfRooms; i++) // iterate over actual room count
            dataModel.RoomDetails[i] = int.Parse(collection["drpRoom" + i]);

        // Generate a ViewModel from your actual DataModel in order to display.
        RoomDetailsViewModel viewModel = new RoomDetailsViewModel(dataModel);

        // display back the view using the viewModel.
        return View(viewModel);
    }
    catch
    {
        // error handling...
        return View();
    }
}

I omitted all data validation stuff for brievity, you get the idea! OTH!

matthew.perron
Cheers :) Going to give this ago and see how it works out.
Jaimal Chohan