Jamie Street
Jamie Street

Reputation: 1547

Sending Complex Data to ASP MVC view

I've been struggling to research an answer to this question as I cannot come up with the correct search terms.

Basically I have 2 IEnumerable<T>'s in my controller, below is the code for the attempt I made.

Controller:

IEnumerable<Room> allRooms = RoomHelper.FindAllRooms();

    foreach (var room in allRooms)
    {
        IEnumerable<Bunk> associatedBunks = RoomHelper.FindAssociatedBunksByRoom(room);
        if (associatedBunks.Count() > 0)
        {
            ViewData["Room_"+room.RoomId] = associatedBunks;
        }
    }

And I'm trying to send them to the view in a way that I can do two foreach loops that will cycle through one set of data (in this case the Room objects and will then using the Room.RoomId key cycle through another IEnumerable which contains the associated data.

My view looks like this but is showing parse errors:

@foreach (var room in ViewBag.Rooms)
{
    <h2>@room.RoomName</h2>

    @if (ViewData["Room_" + room.RoomId].Count() > 0)
    {
        <ol>
            @foreach (var bunk in ViewData["Room_" + room.RoomId])
            {
                <li>@bunk.BunkId</li>
            }
        </ol>
    }
}

The end result I'm looking for in the HTML is something like:

<h2>Room 1</h2>
<ol>
    <li>Bunk 1</li>
    <li>Bunk 2</li>
</ol>

<h2>Room 2</h2>
<ol>
    <li>Bunk 3</li>
    <li>Bunk 4</li>
</ol>

What is the best practice in ASP.NET MVC 4 with EF5 to achieve this kind of result when passing "multidimensional" (is this multidimensional?) data?

Upvotes: 0

Views: 217

Answers (3)

Sandeep Kumar
Sandeep Kumar

Reputation: 1543

As per description given by you it seems that Bunk is associated with rooms. If that's the case then Bunk may have some id for pointing to room it belongs. Now you can create a ViewModel like this

public class BunkViewModel:Bunk
{       
    public BunkViewModel()
    {
        Mapper.CreateMap<Bunk,BunkViewModel>();
    }

    //I'm assuming that you already have some id in bunk to point to room it belongs. 
    //But writing it here to make it clear
    public int RoomId { get; set; }

    public string RoomName { get; set; }

    //Use AutoMapper to Map
    public static BunkViewModel Map(Bunk source)
    {
        return Mapper.Map<Bunk,BunkViewModel>(source);    
    }
}

Now in your controller

public ActionResult ActionName()
{
    var result = new List<BunkViewModel>();
    var rooms = RoomHelper.FindAllRooms();
    var bunks = BunkHelper.GetAllBunks();

    foreach(var bunk in bunks)
    {
        var bunkViewModel = BunkViewModel.Map(bunk);
        var room = rooms.FirstorDefault(r=>room.RoomId == bunk.RoomId);

        bunkViewModel.RoomId = room.RoomId; //No need to set if you already have this id in bunk
        bunkViewModel.RoomName = room.RoomName;

        result.Add(bunkViewModel);
    }

    return View(result.);
}

Now in your view you can do like this

@model List<MyApplication.ViewModels.RoomViewModel>

@foreach(var bunk in Model)
{
    //Print it here as you want..
}

Upvotes: 0

Swifty
Swifty

Reputation: 1432

Use a code block in your view instead of adding an '@' in front of each C# statement:

@{
 foreach (var room in ViewBag.Rooms)
 {
   @Html.Raw("<h2>" + room.RoomName + "</h2>");

  if (ViewData["Room_" + room.RoomId].Count() > 0)
  {
   @Html.Raw("<ol>");

   foreach (var bunk in ViewData["Room_" + room.RoomId])
   {
    @Html.Raw("<li>" + bunk.BunkId + "</li>");
   }

   @Html.Raw("</ol>");
  }
 }
}

You should avoid the use of @HtmlRaw("") as far as possible as it has a XSS vulnerability. But this should put you on the right track.

Upvotes: 0

Roy Dictus
Roy Dictus

Reputation: 33139

Don't rely on ViewData. Store the data that you want to pass on to your view in a proper ViewModel:

public class RoomViewModel
{
     List<Room> Rooms { get; set;}

     ...
}

Store your data in one of those.

Your Controller method then returns an instance of it:

public RoomViewModel GetRooms(int someParameter)
{
    RoomViewModel result = new RoomViewModel();
    result.Rooms = RoomHelper.Something(someParameter);
    ...
    return result;
}

Your View declares its model on top:

@model MyApplication.ViewModels.RoomViewModel

and hence you use it in your View.

<h2>@Model.Rooms.Count rooms found</h2>

etc.

Upvotes: 3

Related Questions