1

I'm trying to filter a list of entities and update the partial view on the page with the filtered data. The partial view is returning the correct model with the filtered data, but is not being rendered inside the parent page. Instead it is being rendered in "body" element of an empty HTML page. I've found many topics on this but even though I appear to be following their directions, I'm still having no luck. A fresh set of eyes from the community here may be a huge help.

@model PennLighting.ViewModels.LinecardViewModel
@{
    ViewBag.Title = "Linecard";
}
<div class="linecard-head">
    @using (Ajax.BeginForm("Index",
        new AjaxOptions
        {
            UpdateTargetId = "linecard"
        }))
    {
        @Html.EditorFor(model => model.Categories)

        <div class="buttons">
            <input type="submit" name="btnFilter" value="Filter" />
            <input type="submit" name="btnShowAll" value="Show All" />
        </div>
    }
</div>
<div id="linecard">
    @Html.Partial("Linecard")
</div>
@section Scripts
{
    @Scripts.Render("~/bundles/jqueryval")
}

public ActionResult Index()
{
    var viewModel = new LinecardViewModel();
    viewModel.Categories = db.Categories
        .OrderBy(c => c.Name).ToList();
    viewModel.Manufacturers = db.Manufacturers
        .OrderBy(m => m.Name).ToList();
    return View(viewModel);
}

public ActionResult Index(string btnFilter, string[] selectedCategories)
{
    var viewModel = new LinecardViewModel();
    var selectedMfrs = new List<Manufacturer>();
    if (btnFilter != null && selectedCategories != null)
    {
        var categoryIds = selectedCategories.Select(c => int.Parse(c)).ToArray();
        if (categoryIds != null)
        {
            selectedMfrs = db.Manufacturers
                .Where(m => m.Categories.Any(c => categoryIds.Contains(c.ID)))
                .OrderBy(m => m.Name).ToList();
        }
    }
    else
        selectedMfrs = db.Manufacturers.OrderBy(m => m.Name).ToList();
    viewModel.Manufacturers = selectedMfrs;
    return PartialView("Linecard", viewModel);
}

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/themes/base/css", "~/Content/css")
</head>
<body>
    <div id="container" class="round-bottom">
        <div id="header">
            <div id="header-left">
                <div id="logo">
                    <a href="@Url.Content("~/")">
                        <img src="@Url.Content("~/Content/Images/logo.png")" alt="Penn Lighting Associates" /></a>
                </div>
            </div>
            <div id="header-right">
                <ul class="nav">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "Index", "About")</li>
                    <li>@Html.ActionLink("Linecard", "Index", "Linecard")</li>
                    <li>@Html.ActionLink("Events", "Index", "Events")</li>
                    <li>@Html.ActionLink("Gallery", "Index", "Gallery")</li>
                    <li>@Html.ActionLink("Contact", "Index", "Contact")</li>
                    <li><a href="http://oasis.pennlighting.com:81/OASIS/desk/index.jsp" target="_blank">
                        Customer Login</a></li>
                </ul>
            </div>
        </div>
        <div id="main">
            @RenderBody()
        </div>
    </div>
    <div id="footer">
        <p>
            Copyright &copy; 2008 Penn Lighting Associates</p>
    </div>
    @Scripts.Render("~/bundles/jquery")
    @RenderSection("scripts",false)
</body>
</html>

So what am I missing? Thanks!

3 Answers3

0

Without seeing more of your solution, it's a bit fuzzy, but I believe you want to still return the Index and pass the model data into the Partial in your view. The way you are doing it would return only the partial view, which is why you're getting those results.

So in the filtered index:

return View(viewModel)

And in the index view, pass the data to the partial, which I assume without seeing has the right model association to display.

UPDATE

If you're looking to dynamically pull a subset of data and leave the rest untouched, then do an AJAX POST with the filter information to the action specified for the partial view. Take the data results and place them in the Linecard div.

There are many ways to send the data (bundle by JSON, serialize form, individual data points). Here are some examples:

http://brandonatkinson.blogspot.com/2011/01/using-jquery-and-aspnet-mvc-to-submit.html

MVC ajax json post to controller action method

Community
  • 1
  • 1
Christian Duvall
  • 399
  • 1
  • 10
  • I'm intentionally using partial views so that my check boxes aren't reset on every postback. Using a partial view seemed like the most concise way to avoid this. –  Jul 07 '13 at 15:45
  • Then you should be doing an AJAX POST to the partial view controller, then populating the Linecard div with the contents. – Christian Duvall Jul 07 '13 at 15:47
  • Thanks for the suggestion. I am new to MVC and even newer to using it with AJAX. Are there any examples online that illustrate this approach well? –  Jul 07 '13 at 15:54
  • Added a couple of links. Google around for MVC POST AJAX Form Serialize and you'll get some varied results. – Christian Duvall Jul 07 '13 at 16:00
  • Thanks again for your input Xian... going to check these out this afternoon and will follow up if I make any progress. –  Jul 07 '13 at 16:36
0

You cannot have 2 actions on the same controller with the same name accessible on the same HTTP verb. You might want to decorate your Index contorller action that is invoked with an AJAX call and returns a partial with the [HttpPost] attribute:

[HttpPost]
public ActionResult Index(string btnFilter, string[] selectedCategories)
{
    ...
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • This made no difference unfortunately. –  Jul 07 '13 at 15:44
  • I guess you are not showing us your real code then. Because you wouldn't even have been able to invoke the first `Index` action if your second action wasn't decorated with the `[HttpPost]` attribute. Could you show your real code? Also look at your javascript debugging console in the browser. Are there some errors? In the Network tab can you see the AJAX request being sent to your application? What does the server respond to it? – Darin Dimitrov Jul 07 '13 at 15:44
  • I am showing my code as it is right out of Visual Studio. I'm looking for help, not to deceive people and waste my time. –  Jul 07 '13 at 15:47
  • All that I am saying is that if this was your real code you would have gotten an exception because you cannot have 2 actions with with same name on the same controller accessible on the same verb. Are the 2 Index actions defined in the same controller? – Darin Dimitrov Jul 07 '13 at 15:47
  • No Javascript errors on either the parent view on load or when the partial view is loaded by itself –  Jul 07 '13 at 15:48
  • That is my "real" code. There were no exceptions. Perhaps you are just wrong about that since the two Index methods take different parameters. Let's move on from this point to the real issue though. –  Jul 07 '13 at 15:50
  • 2
    He's not incorrect, this is a hard rule, unless there's something major not being shown. – Christian Duvall Jul 07 '13 at 15:55
  • @DomRocco, it doesn't matter what arguments your Index actions are taking as long as they have the same name and one of them is not decorated with an attribute like `[HttpPost]`. Try creating a controller containing 2 Index action with different argument and try invoking one of them. You will immediately get an exception. Not at compile-time but at runtime. – Darin Dimitrov Jul 07 '13 at 15:57
  • With all due respect, because I appreciate you both taking the time to respond, but you are both wrong about that... as long as the methods take different parameters you can have multiple methods with the same name. Feel free to try it for yourselves. This is common c# knowledge. An exception is only thrown if I have 2 methods Index() or 2 methods Index(string btnFilter, string[] selectedCategories). –  Jul 07 '13 at 15:59
  • @DomRocco, with all due respect try defining the following controller in a new application and navigate to `/Home/Index` in your browser: `public class HomeContorller: Controller { public ActionResult Index() { return Content("index1"); } public ActionResult Index(string someParameter) { return Content("index2"); } }`. Once you do that come back here so that we can continue our discussion because right now we seem to have some diverging opinions about how ASP.NET MVC works. So let's clarify that first, shall we? – Darin Dimitrov Jul 07 '13 at 16:00
  • I have been trying it. My example is not something I'm doing in notepad and haven't tested. I'm actively developing this with the code above, I am receiving 0 exceptions because the methods do not contain the same parameters. I'm not going to reply to this point anymore. –  Jul 07 '13 at 16:01
  • @DomRocco, did you try the sample code I posted in my previous comment in a new application? We really are trying to help, but if you don't provide all the details it is hard. – Darin Dimitrov Jul 07 '13 at 16:01
  • 1
    @DomRocco - I've tried it a number of times and I have been doing MVC since v1. Unless you are explicit about the verb, it throws an error. It's not a C# rule, it's an MVC rule...these are not just methods, they are actions that a route engine needs to find uniquely. – Christian Duvall Jul 07 '13 at 16:02
  • I don't know how to be any more clear about this so here's a screen shot with my two Index methods and 0 build errors http://i41.tinypic.com/2el7fkp.jpg –  Jul 07 '13 at 16:03
  • @DomRocco, I think you don't understand. Nobody is talking about build errors that you will get. Your application will compile perfectly fine. We are talking about runtime errors. Please try the sample code I posted in my comment in a new MVC application to understand what we are talking about. – Darin Dimitrov Jul 07 '13 at 16:05
  • 1
    HUZZAH! There's the answer. You explicitly added the [HttpPost], which is why you don't get runtime errors. Now Darin can sleep well at night. :) – Christian Duvall Jul 07 '13 at 16:07
  • There are no runtime errors in Visual Studio when I go to the page and start firing off methods in the UI. There are no runtime errors in my Javascript console. –  Jul 07 '13 at 16:07
  • 1
    @DomRocco, remove the `[HttpPost]` attribute from your second controller action. Now run your application and navigate to the first action. What do you get at runtime in your browser? – Darin Dimitrov Jul 07 '13 at 16:08
  • I don't get build errors whether I have HttpPost or not. It's also important to note that if I call the method something completely different, that I get the exact same behavior. –  Jul 07 '13 at 16:08
  • 1
    @DomRocco, once again: you won't get build errors, that's normal. We are not saying that you will get build errors. Run the application (`F5`) and navigate to the Index action in your browser after having removed the HttpPost attribute (your original code shown in your question). – Darin Dimitrov Jul 07 '13 at 16:09
  • @DomRocco - This is spiraling down the wrong place. YES, you'll get the same issue, because you're asking the server to get a complete page and not just asking it to replace the section you want. Please follow my answer above to get to resolution. – Christian Duvall Jul 07 '13 at 16:11
  • Just to humor you, here is a screen shot of that http://i41.tinypic.com/n3t5rd.jpg... but again even if I call it something other than Index and replace the Index method reference in my UI, my problem is exactly the same - the partial view is rendered without the parent layout so to get hung up on method names (which you are wrong about anyway) totally misses the point. –  Jul 07 '13 at 16:11
  • Darin, that just doesn't happen. There are no errors. You are wrong. No +1 for you. Please continue about your day if you have nothing else to contribute about. –  Jul 07 '13 at 16:12
  • @DomRocco, I think you completely misunderstood what we tried to explain here. That's really sad. Good luck with the particular problem. – Darin Dimitrov Jul 07 '13 at 16:13
  • Again: If I call my second Index method something completely different, I still have the same exact problem. So the method name and whether or not I'm including HttpPost clearly wasn't the issue. My partial view loads exactly as it should, and error free, just in the wrong place. That means that regardless of what I call my method, that your input did not solve the issue. –  Jul 07 '13 at 16:35
  • I agree that adding `[HttpPost]` might not have solved the issue. Maybe the issue is related to something else. My point was that without this attribute, your code would have thrown an error when you tried to access the first `Index` action in your browser. But since you don't want to listen to me and try adding the following in a new application to see what I was talking about: http://pastebin.com/KwWmQLJF – Darin Dimitrov Jul 07 '13 at 16:37
0

The problem was that my jqueryval bundle was missing the jquery.unobtrusive-ajax.js file. My code works as is once that was included.