Reputation: 169
I am trying to make a view which will have Partial Views being generated dynamically. Each Partial view is having a TextBox
in which users put the name of a merchant.
Below is my view code:
@model BrightMediaTest.merchant
@{
ViewBag.Title = "AddMerchant";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryval")
<h2>AddMerchant</h2>
@Ajax.ActionLink("Add More", "AddMerchantPartial", "MerchantDB", new AjaxOptions { UpdateTargetId = "ajax-partial-view-box", InsertionMode = InsertionMode.InsertAfter })
@using (Html.BeginForm("AddMerchant", "MerchantDB", FormMethod.Post, new { }))
{
<ul style ="list-style: none;">
<li>
@Html.LabelFor(m => m.merchantName)
</li>
<li>
@Html.TextBoxFor(m => m.merchantName)
</li>
</ul>
<div id="ajax-partial-view-box">
</div>
<input type="submit" value="Add" />
}
As you can see there is a ActionLink in the Code "Add More", which actually adds partial view in the div "ajax-partial-view-box".
So, what I want to achieve is that when I submit the form. I want to take the text of all the TextBoxes which are added in the div "ajax-partial-view-box" dynamically by clicking the link "Add More".
There is no id associated with the TextBoxes in the partial views. Any help or suggestions is appreciated.
Here is my partial view code:
@model BrightMediaTest.merchant
<ul style="list-style: none;">
<li>
@Html.LabelFor(m => m.merchantName)
</li>
<li>
@Html.TextBoxFor(m => m.merchantName)
</li>
</ul>
So, I am trying to add all those merchants names in the database when the form is submitted. I have an Action "AddMerchant" which i will use to add all those merchant name in the database.
My merchant ViewModel is as follows:
namespace BrightMediaTest
{
using System;
using System.Collections.Generic;
public partial class merchant
{
public merchant()
{
this.stores = new HashSet<store>();
}
public long merchantID { get; set; }
public string merchantName { get; set; }
public virtual ICollection<store> stores { get; set; }
}
This code was generated using Entity Framework.
Thanks
Upvotes: 1
Views: 1410
Reputation: 14250
What you want to do is lose the AjaxHelper. You'll need to take more control over your merchant parital insertion.
<a href="@Url.Action("AddMerchantPartial", "MerchantDB")" class="add-merchant">Add More</a>
Wire this up with jQuery. Use index
to track your merchants added to the form so you can uniquely identity them later.
var index = 1; // start with 1 because your form already has a static one
$(".add-merchant").on("click", function(event) {
event.preventDefault();
$.ajax({
url: $(this).attr("href"),
method: "GET",
data: { index: index }
})
.done(function(partialViewResult) {
$("#ajax-partial-view-box").append(partialViewResult);
});
});
Modify your action
public ActionResult AddMerchantPartial(int index)
{
ViewBag.Index = index;
return View(new merchant());
}
Now in your partial you need to include the index and manually write the input elements.
@model merchant
@{
var index = ViewBag.Index as int;
var id = Model.merchantName + "_" + index + "_"; // merchantName_i_
var name = Model.merchantName + "[" + index + "]"; // merchantName[i]
}
<ul>
<li><label for="@id">@Model.merchantName</label></li>
<li><input id="@id" name="@name" type="text" value="@Model.merchantName" /></li>
</ul>
Normally, I refrain from using ViewBag. You might consider adding index
to the view model.
Your main form becomes
@using (Html.BeginForm("AddMerchant", "MerchantDB", FormMethod.Post, new { }))
{
var id = Model.merchantName + "_0_";
var name = Model.merchantName + "[0]";
<ul style ="list-style: none;">
<li>
<label for="@id">@Model.merchantName</label>
</li>
<li>
<input id="@id" name="@name" type="text" value="" />
</li>
</ul>
<div id="ajax-partial-view-box"></div>
<input type="submit" value="Add" />
}
And your post method would be
[HttpPost]
public ActionResult AddMerchant(List<merchant> merchants)
{
...
}
Upvotes: 0
Reputation: 2403
Ok, so I recreated a sample of your issue and it boils down to the fact that you can't post a list without specifying an index in the name attribute. See: MVC Form not able to post List of objects
At the end of the day, before the user clicks submit you will have n merchantName inputs. On your controller post action you will have something like this:
[HttpPost]
public ActionResult AddMerchant(List<merchant> merchant)
{
//post logic
}
In your current setup, the parameter will be null, BUT your form values in your HttpContext.Request will not be, they will look, something like this:
{merchantName=test1&merchantName=test2}
You need to specify where those inputs are supposed to bind to, right now they are lost sheep in a huge pasture. That is done by specifying an index of the object that these inputs belong to.
Such as: merchant[i].merchantName
where i is some index.
Once the partials are added they need to have an object class name and an index prepended to the merchantName value. Your html, before the user clicks add, would look something like this:
<ul style="list-style: none;">
<li>
<label for="merchantName">merchantName</label>
</li>
<li>
<input id="merchantName" name="merchant[0].merchantName" value="" type="text">
</li>
</ul>
<div id="ajax-partial-view-box">
<ul style="list-style: none;">
<li>
<label for="merchantName">merchantName</label>
</li>
<li>
<input id="merchantName" class="valid" aria-invalid="false" name="merchant[1].merchantName" value="" type="text">
</li>
</ul>
<ul style="list-style: none;">
<li>
<label for="merchantName">merchantName</label>
</li>
<li>
<input id="merchantName" class="valid" aria-invalid="false" name="merchant[2].merchantName" value="" type="text">
</li>
</ul></div>
<input value="Add" type="submit">
Then you form data will look something like:
{merchant%5b0%5d.merchantName=test1&merchant%5b1%5d.merchantName=test2&merchant%5b2%5d.merchantName=test3}
And your action parameter will have 3 values in it with the correct data.
Now, how you do this is another matter. There are a number of ways to handle it through Razor or Javascript
Upvotes: 1