-1

I am making an Ajax call to a Controller Action using .get but the parameter is always null when the Controller Action fired. The trigger is a .on(change) event in a jQuery script contained in my _Layout.cshtml. I posted this question earlier, but the thread got trashed with unrelated chatter. Can someone help me troubleshoot why this is happening? Here is the code:

Partial View: ~/Views/Shared/_LanguageListPartial.cshtml

@Html.DropDownListFor(
    x => x.SelectedLanguage,
    Model.Languages,
    new { @class = "form-control" }
)

_Layout.cshtml

<form action="/Account/ListPartial" method="post"
    class="navbar-form navbar-right nopadding" role="" style="margin: 8px 0;">
    @{Html.RenderAction("LanguageListPartial", "Account");} 
</form>

<div id="test"></div>

GET: /Account/LanguageListPartial

[AllowAnonymous]
[ChildActionOnly]
public ActionResult LanguageListPartial()
{
    // Retrieve user's language preference. Default = en-US
    string SelectedLanguage = GetLanguage();

    var model = new LanguageListPartialViewModel();

    model.Languages = GetLanguageList();
    model.SelectedLanguage = SelectedLanguage;

    return PartialView("_LanguageListPartial", model);
}

GET: /Account/TestPartial (Test Action for .on(change) event)

[AllowAnonymous]
public ActionResult TestPartial(string SelectedLanguage)
{
    // Set Language selection in cookie and user profile
    SetLanguage("SelectedLanguage");

    var model = new LanguageListPartialViewModel();

    // Create List<SelectedItemList> of Languages
    model.Languages = GetLanguageList();

    // Set user's Language preference for dropdown
    model.SelectedLanguage = SelectedLanguage;

    return View(model);
}

I haven't been able to completely debug the above code, but the dropdown renders as expected:

<form method="post" action="/Account/ListPartial">
    <select name="SelectedLanguage" id="SelectedLanguage">
        <option value="en-US">English</option>
        <option value="fr-CA">Francais</option>
        <option value="pt-BR">Portugues</option>
        <option value="es-MX">Espanol</option>
    </select>
</form>

<div id="test"></div>

At the bottom of _Layout.cshtml I have this jQuery:

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryUI")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)

<script type="text/javascript">
    $(document).ready(function () {
        $(function () {
            $('#SelectedLanguage').on('change', function () {
                var a = $(this).val();
                $('#test').load("/Account/TestPartial/" + a);
                return false;
            });
        });
    });
</script>

</body>
</html>

The problem is that $(this).val() == null no matter what I try. I don't see anything wrong with any of this code and hoped a sharper eye than mine might see what is wrong. I've tried IE, Firefox and Chrome. All give the same result. I've tried moving the block into the PartialView, but then the Controller Action doesn't even get fired.

Am I violating some rule of structure with the placement of the jQuery? I have other jQuery scripts in various pages and they all work, though this is the only one I've tried in a Layout.

One other really weird thing is that for some reason this script doesn't show up in Firefox for debugging. I don't think I've ever had that problem before, but it just don't show up under Scripts. Although, it's definitely getting executed since when I make a change in the dropdown the Controller Action is being called.

EDIT #1

Viewing in Fiddler, I see that the jQuery is actually working:

GET http://localhost:59655/Account/TestPartial/pt-BR HTTP/1.1
X-Requested-With: XMLHttpRequest
Accept: text/html, */*; q=0.01
Referer: http://localhost:59655/Account/Login?ReturnUrl=%2F
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko
Host: localhost:59655
DNT: 1
Connection: Keep-Alive
Cookie: __RequestVerificationToken=8mK4-p6MrZCx6Iw6dvdad70QvjenwUbW6S0uxxpW7LxkAWn7wzLXompOz59o9Oq2GEt2A7sHvYZXKMOOJqnXGuCshKyHQsNFCJ62rhf2YIA1

Even though pt-BR is being passed to the Controller Action TestPartial, SelectedLanguage is null.

So at this point I feel that _Layout.cshtml coding is correct (including the jQuery). The Partial View code works and renders good HTML. The problem is with TestPartial() but I don't have any ideas as to why it's wrong. :S

EDIT #2

I found an interesting article by a guy who was having this same problem with ASP.NET MVC. He indicates that this problem happened to him when the Controller Action parameter was named the same as one of the model members. My parameter was named the same as the related model property, but renaming it made no difference. The article just suggests to me that there may be some really obscure reason why this is happening.

EDIT #3

As per the suggestion by @Rune, I changed the parameter id so it is now TestPartial(string id). This didn't make any difference as id is still null when called by the jQuery script. I have other Controller Actions that have varying parameter names other than id and they work as I would expect. When I configure a route as suggested by @Rune I get an error message saying that TestPartial.cshtml could not be found and showing all of the locations that were checked.

rwkiii
  • 5,368
  • 17
  • 60
  • 102
  • Your code is working, http://jsfiddle.net/a2PHn/ – Adil Jun 26 '14 at 04:21
  • Yes, the event is fired and Adil, please see my edit. – rwkiii Jun 26 '14 at 04:37
  • Did you configure your routes to match the "selectedLanguage" parameter? Something like "{controller}/{action}/{selectedLanguage}"? – Rune Jun 26 '14 at 05:29
  • I have other Controller Actions that work fine. I have Controller Actions configured just like this one - they accept a country code like "USA" or "CAN". In your example I think {selectedLanguage} is just a placeholder? I mean, it doesn't have to be named literally, does it? That would require a lot of routes for an app if that were the case. Doesn't {controller}/{action}/{id} suffice? {id} could be anything - a number, a string? I'm only guessing. – rwkiii Jun 26 '14 at 05:34

2 Answers2

1

You need to configure your routes to capture the selected language. Something like

routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{selectedLanguage}",
                defaults: new { controller = "Home", action = "Index", selectedLanguage = "en-US" }
            );

The central issue is this: you have to somehow tell ASP.NET MVC that you want the last part of your URL to be associated with the selectedLanguage argument - how could MVC ever guess that on its own?

Alternatively, if you have the default route setup

routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );

you will have to change your action to use the id parameter

ActionResult TestPartial(string id) { }
Rune
  • 8,182
  • 3
  • 32
  • 47
  • I changed the parameter to `string id`, but it's still null. I'm going to read more on what you've said because I didn't know the parameter name had to match as you say. I assumed the route was about structure, which in this case I thought adhered to the default route configuration. – rwkiii Jun 26 '14 at 14:44
  • one of the responses I received along the way recommended I try using jQuery .get to make this call. I made that change and assumed it was good code. As a result I left it in place. Just now I reverted back to my original implementation of the jQuery call and it worked with the parameter name as id! To test that changing the parameter name from selectedlanguage to id had anything to do with the success I renamed the parameter back to selectedlanguage and it returned null. You were right! Thank you so much. ;) – rwkiii Jun 26 '14 at 15:27
0

I like to do my script tags like this - you could also try console.log() in the body of your on event handler, to make sure all the elements are selected properly.

<script type = "text/javascript" >
    function($){
       $(document).ready(function(){

       });
    })(jQuery);
</script>
ArtisticPhoenix
  • 20,683
  • 2
  • 18
  • 34