0

I am populating DropDownList from in-memory data and getting this error on POST.

The ViewData item that has the key 'Position' is of type 'System.String' but must be of type 'IEnumerable'.

Model:

public class StaffModel
{
    public int id { get; set; }
    public string Email { get; set; }
    [DataType(DataType.Password)]
    public string Password { get; set; }
    [DataType(DataType.Password)]
    public string PasswordConfirm { get; set; }
    public string Emp_Name { get; set; }
    public string Emp_Address { get; set; }
    public string Phone { get; set; }
    public string Position { get; set; }
    public List<SelectListItem> Positions { set; get; }

}

Controller:

public ActionResult Register()
    {

        IEnumerable<SelectListItem> position = db.Positions.Select(p => new SelectListItem
        {
            Text = p.Position_Title,
            Value = p.Position_ID.ToString()
        });
        ViewBag.Position = position;
        return View();
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Register(StaffModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                Employee em = new Employee
                {
                    Employee_Name = model.Emp_Name,
                    Address = model.Emp_Address,
                    Phone = model.Phone,
                    Position_ID = Convert.ToInt32(db.Positions.Where(p => p.Position_Title == model.Position).Select(p => p.Position_ID)),
                };
                db.Employees.Add(em);
                db.SaveChanges();
                return RedirectToAction("Index", "Employees");
            }

        }

        return View(model);
    }
enter code here

HTML/Razor:

<div class="form-group">
        @Html.LabelFor(model => model.Position, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownList("Position",null, htmlAttributes: new { @class = "form-control" } )
            @Html.ValidationMessageFor(model => model.Position, "", new { @class = "text-danger" })
        </div>
    </div>
Grizzly
  • 5,873
  • 8
  • 56
  • 109
bao4461826
  • 41
  • 1
  • 5
  • I apologize, I overread that this is happening on post.. you have to declare the `ViewBag.Position` in both `HttpGet` & `HttpPost` Action Methods, most likely above your `if` statement – Grizzly Feb 17 '17 at 15:01
  • I am also confused on your .Where statement.. `p.Position_Title` should never equal `model.Position` because `model.Position` will be the **value** of the dropdownlist.. not the text.. so basically your saying `.Where(p => p.Position_Title == p.Position_ID.ToString())` – Grizzly Feb 17 '17 at 15:10
  • @BviLLe_Kid how can i fix it? – bao4461826 Feb 17 '17 at 15:21
  • Because you did not populate `ViewBag.Position` in the POST method before your returned the view (as you did in the GET method). And do not use `DropDownList()` - use `DropDownListFor()` and a view model as per the code in the dupe so that you get correct model binding and validation. –  Feb 17 '17 at 22:29

2 Answers2

0

Your binding on the drop down list doesn't look right.

You're model contains Positions which is the data for your drop down. You also have "Position" which I presume is a string that will be bound to the selected value in the drop down.

Change your view to

 @Html.DropDownListFor(x=> x.Position, Model.Positions, new {@class = "form-control"}) )

Then on your post, it looks as if you are trying to get the value selected from the drop down by performing a linq query on the "Positions" list of the model which was used to populate your dropdown. You should now have the selected value in the "Position" property of your model.

So you should say

Position_ID = model.Position

I'd also use a model for your Register View. Something like...

 public class RegisterViewModel
        {
            public IEnumerable<SelectListItem> Positions { get; set; }
            public string Position { get; set; }
        }

Plus the additional fields you need.

The in your Register action method, populate the view model and return the view.

 public ActionResult Register()
        {
            var regModel = new RegisterViewModel
            {
                Positions = db.Positions.Select(p => new SelectListItem
                {
                    Text = p.Position_Title,
                    Value = p.Position_ID.ToString()
                })
            };

            return View("Register",regModel);
        }

You don't need to use ViewBag now.

Hope that helps

Wheels73
  • 2,850
  • 1
  • 11
  • 20
0

it work correctly. thank everybody help me:D

Model:

public class StaffModel
{
    public string Position { get; set; }
    public List<Position> Positions { set; get; }
    public int selectID { get; set; }

}

Controller:

 public ActionResult Register()
    {
        StaffModel st = new StaffModel();
        st.Positions = db.Positions.ToList();
        return View(st);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Register(StaffModel model)
    {           
        if (ModelState.IsValid)
        {

            var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
            var result = UserManager.Create(user, model.Password);
            if (result.Succeeded)
            {
                Employee em = new Employee
                {
                    Employee_Name = model.Emp_Name,
                    Address = model.Emp_Address,
                    Phone = model.Phone,
                    Position_ID = model.selectID,
                    ID_User = user.Id
                };
                db.Employees.Add(em);
                db.SaveChanges();

                return RedirectToAction("Index", "Employees");
            }

            else
                AddErrors(result);
        }
        ViewBag.Position = new SelectList(db.Positions, "Position_ID", "Position_Title");
        return View(model);
    }

HTML/Razor:

<div class="form-group">
        @Html.LabelFor(model => model.Position, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(model=>model.selectID,new SelectList(Model.Positions, "Position_ID", "Position_Title"), htmlAttributes: new { @class = "form-control" } )
            @Html.ValidationMessageFor(model => model.Position, "", new { @class = "text-danger" })
        </div>
    </div>
bao4461826
  • 41
  • 1
  • 5