I have a Razor form with a list/table of items that I'd like to dynamically add items to. You can select the items from a dropdown, click "Add", and the item from the dropdown will be added to the list. I'd then like all of that to be sent via POST when I submit my form and my controller's HttpPost method can handle the input.
Is there a way to dynamically add fields and still be able to accept them as arguments in the HttpPost function?
The first answer is correct in that you can iterate over a form collection to get the values of the dynamically inserted fields within your form element. I just wanted to add that you can utilize some of the neat binding.
The code below accepts a dynamic list of textboxes that were posted against the action. Each text box in this example had the same name as dynamicField. MVC nicely binds these into an array of strings.
Full .NET Fiddle: https://dotnetfiddle.net/5ckOGu
Sample code (snippets for clarity) dynamically adding sample fields
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div id="fields"></div>
<button>Submit</button>
}
<div style="color:blue"><b>Data:</b> #ViewBag.Data</div>
<script type="text/javascript">
$(document).ready(function() {
var $fields = $('#fields');
$('#btnAddField').click(function(e) {
e.preventDefault();
$('<input type="text" name="dynamicField" /><br/>').appendTo($fields);
});
});
</script>
Sample code from the action accepting the dynamic fields in a post.
[HttpPost]
public ActionResult Index(string[] dynamicField)
{
ViewBag.Data = string.Join(",", dynamicField ?? new string[] {});
return View();
}
Screenshot of output
Every combobox/hiddenfield/textbox/... that is included inside the <form> element gets posted on submit. Doesn't really matter if you create them on-fly or have them ready by default. The biggest difference however is that with those created dynamically you can't really utilize that neat binding we're used to. You'll have to perform validation etc. manually as well.
Then you'll have a method like this:
public ActionResult HandleMyPost(FormCollection form)
{
// enumerate through the FormCollection, perform validation etc.
}
FormCollection on MSDN
Related
I have a Razor View which has a section where the user can add new rows for ad-hoc opening/closing times on specific dates. It consists of three controls - a DatePicker, two Select lists and a "delete row" button. Existing saved rows are rendered on page-load through Razor, and any new rows are added via an OnClick event and JavaScript appending largely fixed html to the DOM element. All rows are then saved (or removed as required) on HTTPPost.
I have a new requirement which requires implementation of a much more complicated data-set for these ad-hoc, "user-generated" rows. The HTML for each of these rows is extensive. Is there a more elegant way of injecting Razor within a View on a button click than appending hard-coded HTML in JavaScript?
This depends entirely on your use case, and you did not provide any code in your question, but there's something called Partial View. You can read a basic introduction here.
For your case, I'd do something like this:
Controller
public IActionResult GetNewRow()
{
return PartialView("_NewRow");
}
View
<button id="btnAddRow" class="btn btn-primary">Add new row</button>
<script type="application/javascript">
$(function() {
$("#btnAddRow").on("click", function () {
$.get("/GetNewRow", function success(data) {
$("#WHEREVERYOUAREADDINGROWS").append(data);
});
});
});
</script>
PartialView (_NewRow)
<tr>
<td>Add whatever you need here</td>
<tr>
Note: I didn't try this so the AJAX syntax might be a little off.
I have a selectbox with various key-value pairs. What I want to do, is when I select an item in the selectbox, I want to use that selected key-value pair to show a form (partial view) and populate it with values based on that selected value. I figure I need a callback to my controller or something that returns the partial view, but don't know how to exactly do that since its beyond the typical MVC workflow I've been using. Any links to help me research how to do this would be very appreciated.
See accepted SO answer here Dynamically loading partial view.
If javascript is disabled in the browser you would need a trigger, e.g a button, to fire the postback to all the action.
Assuming you have a view which renders a HTML Select like this
<select id="states">
<option value="1">MI</option>
<option value="2">NY</option>
<option value="3">CA</option>
</select>
<div id="partialContent"> </div>
We will capture the change event of this SELECT element and make an ajax call to a server to get the partial view content
<Script type="Text/javascript">
$(function(){
$("#states").change(function(){
var stateId=$(this).val();
$("#partialContent").load("#Url.Action("StateDetails","State")/"+stateId);
});
});
</script>
This will make an ajax GET call to get the response from StateDetails action method in State controller by passing the parameter id with value as selected value of the HTML Select.
public ActionResult StateDetails(int id)
{
var stateDetail=myRepositary.GetStateDetail(id);
return View(stateDetail);
}
I have the following in my controller:
ViewBag.UserList = userlist.ToList();
return View ();
The userlist have the following 3 fields:
First Name, Last Name, Phone Number
How do I go about creating a list in the view where the user can modify the fields?
I am well aware of using the foreach to loop through the list but how do I program the ability to modify the records?
I also need to know how I can then send this list back to the controller so that I can insert the records into my database.
As you said, iterate the list in the view, Use the TextboxFor() method of each property you want to modify, add a submit button, in the controller action add List<T> list to catch the changes and there you go.
I'll assume this is a web mvc project since it's tagged asp.net-mvc.
the view will render html. the html will contain (at a minimum) a form, inputs for each editable value and a submit button. ultimately the markup will look like this
<form id="?" method="post" action="usercontroller/update">
<input name="users.firstname[0]" value="john"/>
<input name="users.lastname[0]" value="doe"/>
<input name="users.phonenumber[0]" value="555-123-4567"/>
<input name="users.firstname[1]" value="jane"/>
<input name="users.lastname[1]" value="smith"/>
<input name="users.phonenumber[1]" value="555-123-4567"/>
<submit value="update"/>
</form>
on the server you would have a controller
class UserController : BaseClassIfNecessary
{
public ActionResult() Update(User[] users)
{
foreach user update database
return RedirectAction("url");
}
}
i'm using the following post type:
<% using (Html.BeginForm())
{ %>
<%= Html.Hidden("EligiblePages", Model.EligiblePages) %>
.... no elements in list appear
$('.btnAction').click(function() {
$.post("Home/AddProduct", $('form').serialize(), function(retval) { $('#addProductDialog').html(retval); });
});
public class ProductViewModel
{
public List<string> EligibleProducts { get; set; }
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddProduct(string sender, ProductViewModel model)
{
...
}
i'll update this when i get home and can put together a more precise example.
and in my ViewModel that is getting posted i have a list<string> as a hidden input field. for some reason when the post occurs and i inspect the controller post method that field is not coming over correctly. any ideas?
<%
for(int i=0;i<Model.EligiblePages.Count;i++)
Html.HiddenFor(model=>model.EligiblePages[i]);
%>
This would render hidden input elements and would serealize to your model appropriately when then controller function AddProduct gets called.
Based on your View Model, I would expect your form elements to look like this:
<input type="hidden" name="EligibleProducts[0]" value="whatever" />
<input type="hidden" name="EligibleProducts[1]" value="whatever" />
etc.
That's what the default model binder is expecting.
The DefaultModelBinder will expect one or more form elements to be posted to bind to the List<string> where the name of each form element matches the name of the list property on the ViewModel. Phil Haack wrote a good blog post about various collection binding approaches.
If you have the entire collection rendered in one hidden input as seems to be suggested in your question, then what will be sent to the browser will just be one value to bind to the list and not a collection of values. You may want to enumerate over the collection and render each value in a hidden input. You could also implement your own model binder to dictate how the posted values are bound to the ViewModel, although that is probably overkill in this case.
What do you see being posted for the collection if you use a HTTP debugging proxy tool like fiddler?
I have a form to which I want to add extra fields depending on the value of a dropdown list. They would be sets of fields and I was thinking on dynamically changing a div's content with the html from a render partial, which would render a PartialView with the fields I want.
Right now the code for the drop down list is the following
<p>
<label for="CatalogItem.Type"> Type: </label>
<%=Html.DropDownList("CatalogItem.Type",Model.Types, "Choose Type") %>
</p>
<div id = "ExtraInfo">
</div>
And I want to put the extra stuff (fields specialized for the type) in the ExtraInfo div. What would the jQuery code be for this?
Thanks!
#Tony has the right approach but instead of putting your RenderPartial html right into the ".html("add html code inside div here")" you may want to do an ajax call. That way the user isn't downloading a bunch of html he/she may not even see.
something like so:
if ( myval == "someValue")
{
$("#ExtraInfo").load("/dynamic-stuff/1")
}
else if ( myval == "someOtherValue")
{
$("#ExtraInfo").load("/dynamic-stuff/2")
}
This also assumes you have a route set up to handle a url like "/dynamic-stuff/2" and responds with the correct partial view.
First add a css class selector to your dropdown, lets call it 'mydropdown' for now
use something like this:
<script language=”javascript” type=”text/javascript” >
function addtoDiv()
{
$(document).ready(function() {
var myval=$(”#mydropdown”).val(); // get value of dropdown
if ( myval == "somevalue") // check myval value
{
$("#ExtraInfo").html("add html code inside div here"); // add code based on value
}
}}
</script>
Do you need to dynamically add fields? You can add fields with JQuery by doing:
$("").attr("id", "test").addClass("FormLabel").appendTo("#parentElement");
$("").attr("id", "testinput").attr("type", "text").appendTo("#parentElement");
In this way, you can create the fields programmatically.
As an alternative, you can create a JQuery partial view. Create an action method that returns an instance of this partial view, and call that action method using
$.get("/<controller>/<actiontoreturnpartialview>", function(data) {
$("#ExtraInfo").html(data);
});
It makes it easier because then you can rely on server-side logic to render the UI, though I tend to use the client-side approach.
Alternatively, you can create your own HTML helper to do this all, but that would be a lot of work.
HTH.