skylake skylake - 2 months ago 8
C# Question

MVC - DropDownList/PartialView issue - "Viewdata has the key int.. ..must be IUnumerable..."


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


This is the error I get when I'm trying to add a DropDownList via partial view. I tried to follow this solution but I somehow failed to do so due to my low experience in coding.

This is how my code look for the moment:

[HttpGet]
public ActionResult Rating()
{
RateReviewVM model = new RateReviewVM()
{
ReviewId = id,
RatingList = new SelectList(Enumerable.Range(1, 10))
};
return View(model);
}

[HttpPost]
public ActionResult Rating(RateReviewVM model) {

if (!ModelState.IsValid)
{
model.RatingList = new SelectList(Enumerable.Range(1, 10));
return View(model);
}

//...


View for _RatingPartial

@model xxxx.ViewModel.RateReviewVM

<h6>Rate the review</h6>

using (Html.BeginForm()) {

<div class="form-group">


@Html.LabelFor(m => m.SelectedRating)
@Html.DropDownListFor(m => m.SelectedRating, Model.RatingList, "-Please select-", new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.SelectedRating)

</div>

<button type="submit" class="btn btn-default submit">Rate</button>
}
}


This is how I try to display _RatingPartial view

@{
var newRating = new xxxx.ViewModel.RateReviewVM { ReviewId = Model.Id };

Html.RenderPartial("_RatingPartial", newRating);

}


Model

public class RateReviewVM {

public System.Guid Id { get; set; }

public System.Guid UserId { get; set; }

public System.Guid ReviewId { get; set; }

public bool HasLiked { get; set; }

public Nullable<int> Rating { get; set; }

public int SelectedRating { get; set; }

public IEnumerable<SelectListItem> RatingList { get; set; }
}


EDIT: ---

Details View(Main)

@model xxxx.Review

@{
ViewBag.Title = "Details";
}

@*@{
//var newRating = new xxxx.ViewModel.RateReviewVM { ReviewId = Model.Id };

@Html.RenderPartial("_RatingPartial", newRating)

}*@

<h2>Details</h2>

<div>

<h4>Review</h4>
<hr/>
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Title)
</dt>

<dd>
@Html.DisplayFor(model => model.Title)
</dd>

<dt>
@Html.DisplayNameFor(model => model.Description)
</dt>

<dd>
@Html.DisplayFor(model => model.Description)
</dd>
@* and so on.. *@

</dl>
</div>
<p>
@Html.ActionLink("Back to List", "Index")
</p>


Controller for Details

public ActionResult Details(Guid? id) {

Review review = db.Reviews.Find(id);

return View(review);
}


Model Review for Details

public System.Guid Id { get; set; }

public System.Guid CreatorUserId { get; set; }

[Required]
public string Title { get; set; }

[Required]
public string Description { get; set; }

public System.DateTime CreatedDate { get; set; }

//etc - some irrelevant property

public virtual ICollection<RateReview> Users { get; set; }

Answer

Use ViewBag for your dropdrownlist and it will work for partialView too. and then you don't need ViewModels. your model classes are fine to work with.

First add CreateRate action to Reviews Controller

 public ActionResult CreateRate(RateReview rate)
    {
        if (ModelState.IsValid)
        {
            rate.Id = Guid.NewGuid();
            db.RateReviews.Add(rate);
            db.SaveChanges();
            return RedirectToAction("Details", "Reviews", new { id = rate.ReviewId });
        }

        return View();
    }

Modify Details action to create a viewbag data as below

public ActionResult Details(Guid? id)
{

    Review review = db.Reviews.Find(id);
    ViewBag.RatingList = new SelectList(Enumerable.Range(1, 10));

    return View(review);
}

Modify your PartialView as below to target CreateRate action, add a HiddenFor Helper for ReviewId and modify dropdownlistfor to read from ViewBag. I use RateReview Model instead of your ViewModel

@model WebApp.Models.RateReview


@using (Html.BeginForm("CreateRate", "Reviews")) 
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
    <h4>RateReview</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })

    @Html.HiddenFor(model => model.ReviewId)

    <div class="form-group">
        @Html.LabelFor(model => model.SelectedRating, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(model => model.SelectedRating, (ViewBag.RatingList as SelectList), new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.SelectedRating, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
</div>
}

at end your Details View is just fine :

@model WebApp.Models.Review

@{
ViewBag.Title = "Details";
}

@{
    var newRating = new WebApp.Models.RateReview { ReviewId = Model.Id };

    Html.RenderPartial("_RatingPartial", newRating);

}


<h2>Details</h2>

<div>
<h4>Review</h4>
<hr />
...