views:

387

answers:

2

So.. I have a problem. I'm sure almost anybody that tried MVC has had it. Nevertheless I've been unsuccessfull in googling a solution or thinking of one for my self.

The problem is this: I have a list of textboxes that I'd like to edit all at once, and I'd also like to add new items to my list. However, the text binding fails after the first postback.

So I've made a small example to illustrate the problem:

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

    <fieldset>
        <legend>Fields</legend>
        <% foreach(string s in Model) { %>
        <p>
          <%= Html.TextBox("list",s) %>
        </p>
        <% } %>
        <p>
            <%= Html.TextBox("newstr") %>
        </p>
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>

    <% } %>

The controller code:

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Edit()
    {
        return View(new List<string>() { "aa", "bb", "cc" });
    }

    // Remove empty strings and add the new one
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(List<string> list, string newstr)
    {
        List<string> res = list.Where(s => !string.IsNullOrWhiteSpace(s)).ToList();

        if (!string.IsNullOrWhiteSpace(newstr))
            res.Add(newstr);

        return View(res);
    }

So, on first GET i return the 3 strings aa, bb and cc, and get 3 textboxes with their text in, as well as en empty textbox for new strings, like this:

aa
bb
cc
Empty.

Now, if I clear the bb string and add "dd" in the empty textbox, I get a return list of "aa","","cc", and "dd" in newstr. This returns a new list of "aa", "cc", "dd" which is what I would expect to see in my checkboxes. Instead I get:

aa
aa
aa
dd (expected empty)

So.. There is something fundamental I didn't get :) Why does it ignore my new datamodel and use some of the old and not all?

I suppose its some kind of viewstate leftover from asp.net, so how do I turn it off? I really want the stateless webpage as advertised.

A: 

Interesting problem. There seems to be a problem inside Html.TextBox(). I debugged your code, and as you can see, the Model in the View does contain the correct List. (BTW, I tested this in Visual Studio 2008).

When you convert the

<%=Html.TextBox("list", s) %>

to a standard

<input id="list" name="list" value="<%=s %>" /> 

it works like it should work. Is this an option?

Pbirkoff
Yeah it does work. The <input name> does the trick. So much for htmlhelpers, at least for now. And everything is an option as long as it works. Thank you both :)
Kristian de Lichtenberg
A: 

If you look at your html source you will see that this has nothing to do with viewstate. When filling inputs after a post the framework will first search the posted values and fill your inputs based on that. Thats why you will get "dd" in your last input. The reason why you get "aa" in the rest of the inputs is that they all have the same name. Your post will look something like this:

list = "aa", list = "", list = "cc"

So when you render a input with the name "list" the framework will search that post and take the first value that matches. This will be "aa" every time. Thats why you get "aa" in all your inputs. You should not have multiple <input type="text" /> with the same name. With unique names you will fix the issue with the looped inputs.

I'm not sure if there is a way to make a <%=Html.TextBox()%> not look in the posted data. But you can always change it to a regular <input type="text" name="newstr" /> and that will work.

Mattias Jakobsson