1

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

12
  • 1
    Sounds like a reasonable plan. What exactly is the problem you are having? Commented May 21, 2015 at 18:16
  • 2
    if all that's in the view is a text box / label, you should probably just do it in javascript. then you can wrap it up in a $.ajax() call to your controller Commented May 21, 2015 at 19:49
  • 1
    You need to show your partial view. Does it also include @Html.TextBoxFor(m => m.merchantName)? (in which case you have invalid html because of the duplicate id attributes). You also need to show the method your posting back to. Is the signature (string[] merchantName)? And why do you have @Scripts.Render("~/bundles/jqueryval") since there is nothing to validate? Commented May 22, 2015 at 0:47
  • @Jasen: My problem is that i am not able to get the data from the text boxes which are there in the partial views. What I want to do is that when I submit the form, It should save all the names from all the partial views into the database. Commented May 22, 2015 at 13:13
  • @DLeh: how will i know which textbox value is picked up since there is no unique id of the textbox...:( Commented May 22, 2015 at 13:14

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

3 Comments

OP is only posting an array of value types not an array of complex objects, so this is all unnecessay - the POST method just needs to be public ActionResult AddMerchant(List<string> merchantName) and it will be correctly bound
@StephenMuecke Yes, that is true. However, this setup allows OP to have a solution where they can introduce more properties for their merchant, if they desire. I would encourage you to post an answer with your solution as I think that is definitely viable.
@AmanThakur it stands for "Original Poster", in this case, the person who asked the question, which would be you.
0

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)
{
    ...
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.