2

My VIEW (success.cshtml) is as below

@model IList<AzSample.Models.Employeelist>    
@using (Html.BeginForm("Save","Home", FormMethod.Post))
{
    @Html.AntiForgeryToken()
    <h2>Employees Details</h2>
    <div>
        <table>
            <tr>
                <th>Id</th>
            </tr>
            @foreach (var emp in Model)
            {
                <tr>
                    <td>@emp.ID</td>
                </tr>
            }
        </table>
        <button type="submit" value="save"  onclick="@Url.Action("Save", "Home")">Save</button>
    </div>
}

My Home Controller is as below

public class HomeController : Controller
{
    public ActionResult Import(HttpPostedFileBase excelfile)
    {
        //Code to get data from Excel sheet
        List<Employeelist> obj = new List<Employeelist>();
        for( int row =2; row <=range.Rows.Count; row++)
        {
            Employeelist emp = new Employeelist();
            emp.ID =((Excel.Range)range.Cells[row,1]).Text;
            obj.Add(emp);
        }
        return View("success", obj);
    }

    [HttpPost]
    public ActionResult Save(List<Employeelist> empLIst)
    {
        // Code fro storing the data got from VIEW.
    }
}

My Model is as below

public class Employeelist
{
    public string ID { get; set; }
}

I am calling import action method from some other page, and reading the data from Excel sheet and showing it on success.cshtml. Till here it works fine.

When ever i click on Save button, the debug point is coming back to Save action method, but the data (i.e. List<Employeelist>, basically all Employeelist.ID's ) is null ? What is missing ?

ismail baig
  • 861
  • 2
  • 11
  • 39
  • What data? You form does not contain any form controls so then is nothing to submit. And why do you have a submit button with `onclick="@Url.Action("Save", "Home")"` which does nothing and makes no sense –  Feb 04 '16 at 09:25
  • @StephenMuecke: The form should atleast send back the same data as was rendered from the XL sheet back to Save action method in this parameter empLIst. But seems to be it send only null. – ismail baig Feb 04 '16 at 10:17
  • Because your form does not contain any form controls (`` etc).so there is nothing to send to the controller –  Feb 04 '16 at 10:18
  • 1
    Assuming you want to send back all the `Employeelist.ID` values, then you need to generate a hidden input or readonly textbox inside a `for` loop (your model needs to be `IList` or use a custom `EditorTemplate` for typeof `Employeelist` –  Feb 04 '16 at 10:27
  • @StephenMuecke: Yes, i want all the Employeelist.ID, I tried by changing the VIEW as follows inside the for loop. @Html.EditorFor(model => @emp.ID). But still its returning null back to my SAVE action. – ismail baig Feb 04 '16 at 10:31
  • Read my last comment :) –  Feb 04 '16 at 10:32
  • No, it seems to be because of something else. still returning null. – ismail baig Feb 04 '16 at 11:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/102593/discussion-between-ismail-baig-and-stephen-muecke). – ismail baig Feb 04 '16 at 12:02
  • If you think `@Html.EditorFor(model => @emp.ID)` works then your wrong - look at the html your generating - duplicate name attributes that have no relationship to your model and duplicate id attributes which is invalid html. Read my comment again. –  Feb 04 '16 at 12:04
  • And if your going to invite me into a chat room, at least have the courtesy to enter it yourself. –  Feb 04 '16 at 12:14
  • yup. sorry i dont have chat facility in my company. The firewall is blocking it. – ismail baig Feb 04 '16 at 12:24
  • 1
    OK, But read my previous comment carefully. I need some sleep, but if you have not worked this out tomorrow, I'll add and answer showing how do do it using both a `for` loop and an `EditorTemplate` –  Feb 04 '16 at 12:34
  • sure, thanks that should be great. – ismail baig Feb 04 '16 at 13:22
  • 1
    Georg Patscheider has has already added an answer showing you how to use a `for` loop. For more information on why using a `foreach` loop does not work, and for an example of using an `EditorTemplate`, refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable) –  Feb 04 '16 at 20:56

2 Answers2

4

The data for the empList is never submitted with the form. You should render <input> fields to submit your data.

 @for(int i = 0; i < Model.Count(); ++i) {
    @Html.HiddenFor(m => m[i].Id)
    // send other properties        
 }

It is important that you bind to indexed properties so the MVC modelbinder can bind this as a collection. @Html.HiddenFor(m => m.Id) will not work.

See also Model Binding to a List MVC 4

--Edit--

As Stephen has pointed out, the modelbinder will try to bind this using the index, so your c# model must implement IList<T>.

Another pitfall are non-sequential indices.

Community
  • 1
  • 1
Georg Patscheider
  • 9,357
  • 1
  • 26
  • 36
  • 2
    OP's model in the view is `IEnumerable` - It needs to be changed to `IList` or this code will throw an exception –  Feb 04 '16 at 12:47
0

You should use this > ASP.NET MVC TempData ?

ASP.NET MVC TempData dictionary is used to share data between controller actions. The value of TempData persists until it is read or until the current user’s session times out. Persisting data in TempData is useful in scenarios such as redirection, when values are needed beyond a single request.

The code would be something like this:


Import Method:
public ActionResult Import(HttpPostedFileBase excelfile)
    {
        //Code to get data from Excel sheet
        for( int row =2; row <=range.Rows.Count; row++)
            {
                Employeelist emp = new Employeelist();
                emp.ID =((Excel.Range)range.Cells[row,1]).Text;
                obj.Add(emp);
            }
        TempData["doc"] = obj;
        return View("success", obj);
    }

View:

@model IEnumerable<AzSample.Models.Employeelist>    
@using (Html.BeginForm("Save","Home", FormMethod.Post))
{
@Html.AntiForgeryToken()
<h2>Employees Details</h2>
<div>
    <table>
        <tr>
            <th>Id</th>

        </tr>
 @{var list = (List<AzSample.Models.Employeelist>)TempData["doc"];}
@{TempData["doc"] = list;}
        @foreach (var emp in list)
        {
            <tr>
                <td>@emp.ID</td>
            </tr>
        }
    </table>

    <button type="submit" value="save"  onclick="@Url.Action("Save", "Home")">Save</button>
</div>
}

Save Method:

[HttpPost]
public ActionResult Save()
{
   if (TempData["doc"] != null)
    {
        // Your code will be here
    }
}
Smit Patel
  • 2,992
  • 1
  • 26
  • 44
  • I got the following error for this approach. CS1579: foreach statement cannot operate on variables of type 'object' because 'object' does not contain a public definition for 'GetEnumerator' – ismail baig Feb 04 '16 at 10:15
  • Its removes the error, but the answer is still wrong and does not work - suggest you try it yourself. –  Feb 04 '16 at 12:13
  • Can you tell me how? – Smit Patel Feb 04 '16 at 12:16
  • 2
    Read my comments in the question and your will understand. `TempData` has nothing to do with OP's issue (and using it would fail anyway - OP is already passing the data to the view in the model correctly and in the POST method `if (TempData["doc"] != null)` will always be `null` because its already been read) –  Feb 04 '16 at 12:20
  • But it will surely work if we fill the Tempdata again, Check the answer, Checked and tested..! – Smit Patel Feb 04 '16 at 12:27
  • 2
    @Smit Sorry, but your answer is not only wrong, its pointless and it does not even address OP's issue, which is there is nothing sent to the POST method because there are no form controls. –  Feb 04 '16 at 12:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/102597/discussion-between-smit-and-stephen-muecke). – Smit Patel Feb 04 '16 at 12:38