views:

714

answers:

3

I have an MVC application which has a set of fields for contact details to be added for a person (Email, Phone, Fax, AIM... etc). Initially I present a dropdown for type of input and and input field for the corresponding data, along with a link to add a further set of fields.

When complete I have a submit button to submit the form.

I am happy with an approach for adding a further set of fields using the add link and javascript, but I can't work out how to do this without javascript.

I would be grateful for some pointers in the best direction to solve this. I am not particularly precious about keeping the add link, it could be a button, but I would rather the url not change in the address bar.

Thanks, Richard

A: 

With jQuery it is pretty easy to insert html elements into the DOM, on the fly, with no postback. It is using javascript, which you said in your header that you didn't want, but you did say it was OK in the question so tell me if you need something else.
So what you really need to figure out is a way to handle the data when sent to the server...

...and that doesn't have to be too hard either. If I'm not mistaken (but I might be) values from input elements with the same name will be handled as an array of values. Thus, if you insert new elements all with a generic name, you should be able to retrieve all the data by iterating over the array on the server.

This html

<input type="text" name="customData" />
<input type="text" name="customData" />

will post data that you can get with this C# code on the server:

public ActionResult DoCoolStuff(FormCollection postedValues) {
    foreach(string data in postedValues.customData) {
         // This is where the cool stuff goes
    }
    Return RedirectToAction("Index");
}
Tomas Lycken
Tomas, thanks for your answer and sorry I can see now how the question was unclear and have edited. I am happy with meant that I know how I can do it with javascript. However I want to be fully inclusive and therefore have a solution for browsers without javascript.
Richbits
Ah! I'll see if I can come up with something... One way to do it (although it might not be optimal) is of course Matthews solution below, and saving the number of fields in a session variable that you increment on each postback. In MVC, you can have a link that posts back to another ActionMethod, which adds a field and serves the view again. Actually, I think I have a pretty neat idea of how to do this - if I find some extra time I'll put it down in writing in another answer =)
Tomas Lycken
A: 

This is basically the client side of the answer. If you have to do it without JavaScript and without changing the URL, that basically leaves a POST.

<form action="" method="post">
<input name="field1"/>
<input name="field2"/>
...
<input name="add_field_submit" type="submit" value="Add Field"/>
...
<input name="done_submit" type="submit" value="Submit"/>

On the server, you detect whether they clicked Add Field (add_field_submit is present) or Submit (done_submit is present). If they clicked Add Field, you add a field and serve the view. Otherwise, it's done.

Matthew Flaschen
Thanks Matthew, I can't try these out just now but I'll be sure to try over the weekend and report back. What I wasn't sure of was how to differentiate between the two server side, but found this answer: http://stackoverflow.com/questions/442704/how-do-you-handle-multiple-submit-buttons-in-asp-net-mvc-framework/443047#443047. I'll try it out along with Tomas's answer below.
Richbits
Yes, my approach could easily be used with Dylan's answer from that link. The only thing to note is he's using the /value/. Above, both name and value are unique (this is allowed, and used by e.g. Google). You could also uses Tomas's method, if you don't mind having an extra form and using a different POST url.
Matthew Flaschen
Thanks Matthew, this works fine.
Richbits
A: 

As Matthew said, if you don't want to change the URL and don't want to use javascript, your best option is a POST request to the server. In ASP.Net MVC this can be pretty neatly done, however. You'll need to modify the View with two additions, and add a new ActionMethod.

The View, part 1
Add an extra form to your view (this is not allowed in WebForms, so it might feel a little strange, but it is perfectly fine in MVC).

<form action="/myController/myView/<%= (ViewData["fieldCount"]+ 1) %>">
    <input type="submit" value="Add custom field" />
</form>

Note the fieldCount variable - this should be passed down from the Controller as presented below:

The Controller
Add the following ActionMethod to overload the one you currently have to display your form:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult myView(int id) {
    ViewData["fieldCount"] = id;
    Return View();
}

I used the variable name id just so you wouldn't have to add another route.

The View, part 2
Now, as you have a known fieldcount, so you can just loop out the fields on the view:

<form action="/myController/SaveData/" method="post">
    ...
    <% for(i=0; i<int.TryParse(ViewData["fieldCount"]); i++) { %>
        <input type="text" name="customData" /><br />
    <% } %>
    ...
</form>

Note that the two forms have different actions - that way, you will never have to worry that clicking one submit button will accidentally post the wrong data.

Tomas Lycken
Thanks Tomas, this looks pretty neat. Though I cannot try it out right now, I'll be sure to try over the weekend and report back.
Richbits
Thanks Tomas, I can't seem to get this to work though and dont understand a couple of things. That is not a problem though since I am happy with Matthew's solution. Firstly I get a compilation error in pt. 1 <form action... New Line in constant. Secondly I don't really understand how the rest of the form data gets populated back to the form in the controller action here.
Richbits