Search code examples
asp.netasp.net-mvcasp.net-mvc-5viewbag

Pass ViewBag with List to view for foreach loop


I am passing a query result from the controller to a view through a Viewbag but when looping through the Viewbag result I get the error 'object' does not contain a definition for 'Ratings' even though it does show up when debugging. I am not using a model for the query so I cannot cast the list.

How do I send through the list from the query or the query results itself to the view to so I loop through and extract the data?

Controller

var AppQuery = (from ans in db.Answers
                        join ques in db.Questions on ans.QuestionID equals ques.QuestionID
                        join resp in db.Responses on ans.ResponseID equals resp.ResponseID
                        join sec in db.Sections on ques.SectionID equals sec.SectionID
                        where resp.ResponseID == ID && ques.SubSectionName != null
                        select new { SectionName = sec.SectionName, RatingAnswer = ans.RatingAnswer })
 .GroupBy(a => a.SectionName)
 .Select(a => new { SectionName = a.Key, Ratings = a.Sum(s => s.RatingAnswer) });


        ViewBag.Results = AppQuery.ToList();

View

    @{var Results = ViewBag.Results;}

 @foreach (var item in Results)
                                        {
                                            var style = "active";
                                            var condition = "";

                                            if (item.Ratings >= 90)
                                            {
                                                style = "success";
                                                condition = "Excellent";
                                            }
                                            else if (item.Ratings < 50)
                                            {
                                                style = "danger";
                                                condition = "Critical";
                                            }
                                            else
                                            {
                                                style = "active";
                                                condition = "Stable";
                                            }
                                            <tr class="@style">
                                                <td>@item.SectionName</td>
                                                <td>@item.Ratings</td>
                                                <td>@condition</td>

                                            </tr>

                                        }

Thanks for the help!


Solution

  • This is the expected behaviour!. Because you set a collection of anonymous objects to your ViewBag.

    You should be using a strongly typed view model.

    public class RatingVm
    {
      public string SectionName { set;get;}
      public int Ratings { set;get;}
    }
    

    and in your action method,

    public ActionResult Create()
    {
      var results= (from ans in db.Answers
                         join ques in db.Questions on ans.QuestionID equals ques.QuestionID
                         join resp in db.Responses on ans.ResponseID equals resp.ResponseID
                         join sec in db.Sections on ques.SectionID equals sec.SectionID
                         where resp.ResponseID == ID && ques.SubSectionName != null
                            select new { SectionName = sec.SectionName, 
                                         RatingAnswer = ans.RatingAnswer })
     .GroupBy(a => a.SectionName)
     .Select(a => new RatingVm { SectionName = a.Key, 
                                 Ratings = a.Sum(s => s.RatingAnswer) }).ToList();
      return View(results);
    
    }
    

    Now your view should be strongly typed to the type of data we are passing from our action method, which is a collection of RatingVm

    @model List<RatingVm>
    <h1>Ratings</h1>
    @foreach(var item in Model)
    {
      <p>@item.SectionName</p>
      <p>@item.Ratings</p>
    }