Posting Back DropDownList from Strongly Typed View

纵饮孤独 提交于 2021-01-07 03:52:42

问题


This is related to an earlier question on binding a dropdownlist from a database. The dropdownlist is being bound and populated but is throwing an "Object reference not set to an instance of an object" error in the browser when submitting the form.

When debugging, I added a quick watch on the m => m.SelectedDepartment parameter of the Html.DropDownListFor(...) helper method and got: "Cannot convert lambda expression to type 'object' because it is not a delegate type".

View:

@model BudgetDemo.Models.BudgetsActualsViewModel
@using (Html.BeginForm("GetBudgetsActuals", "BudgetsActuals", FormMethod.Post))
{
    @Html.DropDownListFor(m => m.SelectedDepartment, Model.Departments, 
        "Select Department", new { @class = "form-control" })
}

ViewModel:

public class BudgetsActualsViewModel
{
    [Display(Name = "Cost Center/Department")]
    [Required(ErrorMessage = "Cost Center/Department is required.")]
    [StringLength(62)]
    public string SelectedDepartment { get; set; }
    public List<SelectListItem> Departments { get; set; }
}

Controller:

// GET: Render view with dropdowns
public ActionResult GetBudgetsActuals()
{
    repo = new BudgetDemoRepository();
    ModelState.Clear();

    try
    {                
        return View(repo.GetBudgetsActuals());
    }
    catch
    {
        return View("Error");
    }
}

Repository:

public BudgetsActualsViewModel GetBudgetsActuals()
{
    ...
    BudgetsActualsViewModel budgetsActuals = new BudgetsActualsViewModel() 
        { Departments = new List<SelectListItem>() };
    
    // Query returning correct data from DB here

    for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
    {
        budgetsActuals.Departments.Add(                    
            new SelectListItem
            {
                Text = ds.Tables[0].Rows[i]["Department"].ToString(),
                Value = ds.Tables[0].Rows[i]["ListValue"].ToString()
            }
        );
    }

    return budgetsActuals;
}

UPDATE

It's working now. The following code was updated/added to get the form re-rendering after a postback with a success message containing the value of the selected department.

View:

@model BudgetDemo.Models.BudgetsActualsViewModel
@Html.AntiForgeryToken()

@using (Html.BeginForm("GetBudgetsActuals", "BudgetsActuals",  
    FormMethod.Post))
{
     @Html.ValidationSummary(true, "", new { @class = "text-danger" })

     @if (TempData["SuccessMessage"] != null)
     {
         <p class="alert alert-success"
             id="successMessage">@TempData["SuccessMessage"]</p>
     }

    @Html.DropDownListFor(m => m.SelectedDepartment, Model.Departments, 
        "Select Department", new { @class = "form-control" })
    @Html.ValidationMessageFor(model => model.SelectedDepartment, "", 
        new { @class = "text-danger" })    
}

Controllers:

// GET
public ActionResult GetBudgetsActuals()
{
    Populate Department dropdown from DB and Year dropdown (static) here
    repo = new BudgetDemoRepository();
    //ModelState.Clear();

    try
    {
        return View(repo.GetBudgetsActuals());
    }
    catch
    {
        return View("Error");
    }
}

// POST
[HttpPost]
public ActionResult GetBudgetsActuals(BudgetsActualsViewModel model)
{
    try
    {
        repo = new BudgetDemoRepository();
        if (ModelState.IsValid)
        {
            TempData["SuccessMessage"] = "Value of SelectedDepartment is: " 
                + model.SelectedDepartment;
            return View(repo.GetBudgetsActuals(model));
        }
        else
        {
            model.Departments = repo.GetBudgetsActuals().Departments;
            return View(model);
        }
    }
    catch
    {
        return View("Error");
    }
}

Repository - New overloaded method to handle POST

public BudgetsActualsViewModel GetBudgetsActuals(BudgetsActualsViewModel model)
{
    ....
    // Get the data again
    ....
 
    budgetsActuals.SelectedDepartment = model.SelectedDepartment;
    for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
    {
        budgetsActuals.Departments.Add(
            new SelectListItem
            {
                Text = ds.Tables[0].Rows[i]["Department"].ToString(),
                Value = ds.Tables[0].Rows[i]["ListValue"].ToString()
            }
         );
     }   
     return budgetsActuals;
}

回答1:


Modify the controller to have a new api that supports a POST call. Do as follows.

Add this method a get method that is called when the view is loaded, like this:

[HttpGet]
public ActionResult GetBudgetsActuals()
{
    repo = new BudgetDemoRepository();
    ModelState.Clear();

    try
    {                
        return View(repo.GetBudgetsActuals());
    }
    catch
    {
        return View("Error");
    }
}

Add a post method that is called when the form is submitted:

[HttpPost] // Decorate with this attribute
public ActionResult PostBudgetsActuals(BudgetDemo.Models.BudgetsActualsViewModel model)
{
    var selectedDepartment = model.SelectedDepartment;
   // dostuff with the model
   return somethingFromHere;
}

And change the view like this:

@model BudgetDemo.Models.BudgetsActualsViewModel
@using (Html.BeginForm("PostBudgetsActuals", "BudgetsActuals", FormMethod.Post))
{
    @Html.DropDownListFor(m => m.SelectedDepartment, Model.Departments, 
        "Select Department", new { @class = "form-control" })
}

If you are getting an issue with the overload of DropDownListFor method, then you can also try DropDownList method like below:

@using (Html.BeginForm("PostBudgetsActuals", "BudgetsActuals", FormMethod.Post))
{
    @Html.DropDownList("SelectedDepartment", Model.Departments,
        "Select Department", new { @class = "form-control" })
}

UPDATE

// POST
[HttpPost]
public ActionResult GetBudgetsActuals(BudgetsActualsViewModel model)
{
    try
    {
        repo = new BudgetDemoRepository();
        if (model.SelectedDepartment != null)
        { 
            TempData["SuccessMessage"] = "Value of SelectedDepartment is:
                " + model.SelectedDepartment;
        }
        model.Departments = repo.GetBudgetsActuals().Departments;
        return View(model);
     }
     catch
     {
         return View("Error");
     }
}


来源:https://stackoverflow.com/questions/64989958/posting-back-dropdownlist-from-strongly-typed-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!