0

I have a HomeController which has a Navigation ActionResult to perform a query to get the top level elements:

public ActionResult Navigation()
{
    var navigationModel = (from m in db.Navigations where (m.Main == true) orderby m.Position select m);
    return View(navigationModel);
}

I then have a Navigation View which outputs the results like so:

@model IEnumerable<WebApplication1.Models.Navigation>

<ul class="nav sf-menu clearfix">
    @foreach (var item in Model)
    {
        @Html.MenuLink(item.Title, item.Action, item.Controller)
    }
</ul>

I would like so add a second navigation layer so contemplating something like:

public ActionResult Navigation()
{
    var navigationModel = (from m in db.Navigations where (m.Main == true) orderby m.Position select m);
    var contentModel = (from n in db.Contents where (n.NavigationId = navigationModel.Id) orderby n.Position select n);
    return View(navigationModel, contentModel);
}

I get the error Cannot convert method group 'Id' to non-delegate type 'int?'. Did you intend to invoke the method?

I would like also like to pass the second query to the View, something like:

@model IEnumerable<WebApplication1.Models.Navigation>
@model IEnumerable<WebApplication1.Models.Contents>

<ul class="nav sf-menu clearfix">
    @foreach (var item in Model)
    {
        @Html.MenuLink(item.Title, item.Action, item.Controller)
        <ul>
        @foreach (var item in Model)
            {
                @Html.MenuLink(item.Title, "Article", "Home")
            }
        </ul>
    }
</ul>

I realise my use of models may be completely inaccurate, just trying to emphasise what data where.

Any help would be much appreciated :-)

Here are the Navigation and Content classes to assist with any solutions:

Navigation.cs

public partial class Navigation
{
    public int Id { get; set; }
    public string Title { get; set; }
    public Nullable<int> Position { get; set; }
    public bool Main { get; set; }
    public string Action { get; set; }
    public string Controller { get; set; }
}

Content.cs

public partial class Content
{
    public int Id { get; set; }
    public Nullable<int> NavigationId { get; set; }
    public string Title { get; set; }
    public string Content1 { get; set; }
    public Nullable<int> Position { get; set; }
    public string Image { get; set; }
    public string Sub { get; set; }
    public Nullable<bool> Active { get; set; }
    public string Url { get; set; }
    public string Summary { get; set; }
}

Despite the helpful advise I was still left with the error Operator '==' cannot be applied to operands of type 'int?' and 'method group' so tried an alternative method, which is to use a join query, so I have modified the MVC structures as follows:

NavigationViewModel

public class NavigationViewModel
{
    public int NavigationId { get; set; }
    public string NavigationTitle { get; set; }
    public string NavigationAction { get; set; }
    public string NavigationController { get; set; }

    public int ContentId { get; set; }
    public string ContentTitle { get; set; }
}

HomeController

public ActionResult Navigation()
{
    var navigationModel = from c in db.Contents
                            join n in db.Navigations on c.NavigationId equals n.Id
                            where (n.Main == true && c.Active == true)
                            orderby n.Position
                            select new NavigationViewModel()
                            {
                                NavigationId= n.Id,
                                NavigationTitle = n.Title,
                                NavigationAction = n.Action,
                                NavigationController = n.Controller,
                                ContentId = c.Id,
                                ContentTitle = c.Title
                            };

    return View(navigationModel);
}

Navigation

@model IEnumerable<WebApplication1.Models.NavigationViewModel>

@foreach (var item in Model)
{
    @item.NavigationId @item.NavigationTitle @item.NavigationAction @item.NavigationController @item.ContentId @item.ContentTitle
}

So this gets the data, but I have a similar issue to what I started with, how do I now step through the data so I have something like this:

<ul class="nav sf-menu clearfix">
// Loop through items
// Are there multiple intances of the NavigationId?
    // No
    <li>navigation link here</li>
    // Yes
    <li class="sub-menu">navigation link here
        <ul>
            // Loop through all content links
            <li>content link here</li>
            // End loop
        </ul>
    </li>
// End Loop
</ul>
iggyweb
  • 2,373
  • 12
  • 47
  • 77
  • You can't define two models in a view like you did in your last example. Instead, make a ViewModel that will have one of each of those two models you want, and pass that into your view. Then you can access each like so (Model.Navigation and Model.Contents) – Bobo May 22 '14 at 22:40
  • possible duplicate of [MVC 5 Multiple Models in a Single View](http://stackoverflow.com/questions/23536299/mvc-5-multiple-models-in-a-single-view) – Erik Philips May 22 '14 at 22:40

2 Answers2

1

You can use a view model for this:

public class NavigationViewModel
{
    public IEnumerable<Navigation> Navigations { get; set; }
    public IEnumerable<Content> Contents { get; set; }
}

Your view will take this view model:

@model YourNamespace.ViewModels.NavigationViewModel

You're controller will initialize this view model and pass it to the view:

public ActionResult Navigation() {
    var navigations = your query...
    var contents = your other query...

    return View(new NavigationViewModel {
        Navigations = navigations,
        Contents = contents
    });
}

And your view can access both Model.Navigations and Model.Contents.

Neil Smith
  • 2,565
  • 1
  • 15
  • 18
  • Thank you, this looks promising, I'm still getting the error `Operator '==' cannot be applied to operands of type 'int?' and 'method group'` can't figure why both `n.NavigationId == navigationModel.Id` are both ints, but for some reason when I type `navigationModel.` Id does not appear as an option in Visual Studio 2013. – iggyweb May 22 '14 at 22:49
  • I also have the errors `The name 'navigations' does not exist in the current context` and `The name 'contents' does not exist in the current context` any ideas? – iggyweb May 22 '14 at 22:50
  • `int?` implies one of those is a `nullable int`. You really should only ask one question per SO question. Where do you get this new error? – Neil Smith May 22 '14 at 22:51
  • Thinking about it, you're probably getting that error when you're creating your `NavigationViewModel` in your action right? If so, it's probably due to copy pasting. I named the variables `navigations` and `contents` while you originally named the same thing `navigationModel` and `contentModel`. Make sure everything is named correctly. – Neil Smith May 22 '14 at 22:54
  • Yup that took care of those two errors, but still left with `Operator '==' cannot be applied to operands of type 'int?' and 'method group'` – iggyweb May 22 '14 at 23:00
  • If I modify the code to `var contentModel = (from n in db.Contents where (n.NavigationId == 1) && (n.Active == true) select n);` the error goes away, but then that limits the query. – iggyweb May 22 '14 at 23:20
0

Try using == instead of = for your compiler error (unless you really mean to call the delegate which I doubt).

public ActionResult Navigation()
{
    var navigationModel = (from m in db.Navigations where (m.Main == true) orderby m.Position select m);
    var contentModel = (from n in db.Contents where (n.NavigationId.HasValue &&(n.NavigationId.value == navigationModel.Id)) orderby n.Position select n);
    return View(new Tuple<Navigation, Contents> (navigationModel, contentModel));
}

You may have to use a conversion such as toString() if you have casting complications.

For your second issue if you don't want to make a new class use a Tuple (http://www.dotnetperls.com/tuple).

@model Tuple<WebApplication1.Models.Navigation, WebApplication1.Models.Contents>

<ul class="nav sf-menu clearfix">
    @foreach (var item in Model.Item1)
    {
        @Html.MenuLink(item.Title, item.Action, item.Controller)
        <ul>
        @foreach (var item in Model.Item2)
            {
                @Html.MenuLink(item.Title, "Article", "Home")
            }
        </ul>
    }
</ul>
Benj Sanders
  • 481
  • 5
  • 15
  • Tried your suggestion but I still get `Operator '==' cannot be applied to operands of type 'int?' and 'method group'` I've tried cleaning and building the solution to make sure Visual Studio is not caching anything, but still no joy. – iggyweb May 22 '14 at 23:10
  • Are you using the designer to make your dbml? Make sure it assigns the right data type. What's in the Contents part of your dbml? – Benj Sanders May 22 '14 at 23:24
  • No designer, just writing the code directly into Views, Models and Controllers. I have also included the Navigation and Content classes in my original post. – iggyweb May 22 '14 at 23:27
  • do you need to use (Nullible)? can you use (int?) or just int? Either way you need to cast NavigationId to int. var contentModel = (from n in db.Contents where ((int)n.NavigationId == navigationModel.Id) orderby n.Position select n); or use n.NavigationId.value. – Benj Sanders May 22 '14 at 23:35
  • Thank you, tried that still got an error, so I have tried using an inner join instead, which gets the data to the View, but now I need to be able to step through the data. – iggyweb May 23 '14 at 05:17