24

I have a dropdown list in an MVC view. On selection change of dropdown list I want to call specific action method in the controller.

What I have done on view is this :

<%=Html.DropDownList("ddl", ViewData["AvailableList"] as SelectList,
  new { onchange = "this.form.action='MyMethod';this.form.submit();" })%>

Everything is getting compiled. But a runtime exception is thrown when I change the drop down selection, as

"Microsift JScript Runtime Error : Object doesn't support property or method"

How can I redirect to specific action on list selection change event?
How can I pass parameters to this action method?

Jaqen H'ghar
  • 1,839
  • 7
  • 37
  • 66

7 Answers7

23

Do you really need to submit the form? You could redirect:

onchange = "redirect(this.value)"

where redirect is a custom defined function:

function redirect(dropDownValue) {
    window.location.href = '/myController/myAction/' + dropDownValue;
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 1
    I tried this but it only works if I pass the parameter as a query string, for example: window.location.href = '/myController/myAction?param=' + dropDownValue; – fjxx Apr 15 '11 at 02:36
  • 1
    @fjxx, you should be able to fix this by reconfiguring your [URL routing](http://goo.gl/fKcxX). – Shimmy Weitzhandler Nov 25 '12 at 09:55
  • @Darin Dimitrov, is there a way to do this as a one-liner, without defining the function in js? – Shimmy Weitzhandler Nov 25 '12 at 09:56
  • 4
    @Shimmy, yes there's a way: `onchange = "window.location.href='/myController/myAction/' + this.value;"`. – Darin Dimitrov Nov 25 '12 at 10:39
  • @DarinDimitrov and what if I want to use `Url.Action`, is there still a way to include the `this.value` from JS in the route values anonym. object (I know I can do this manually `?query=value`, but I prefer `Url.Action`)? – Shimmy Weitzhandler Nov 25 '12 at 10:42
  • 1
    @Shimmy, no there's no way. `Url.Action` runs on the server whereas `this.value` is known only on the client. The proper way to do this is to put this dropdown inside an HTML form with a submit button so that you don't need to use javascript to manually craft urls. – Darin Dimitrov Nov 25 '12 at 15:35
  • awesome! @Html.DropDownList("pagesize", ViewData["listPageSizes"] as SelectList, new { Class = "form-control", onchange = "redirect(this.value)" }) – Nick Kovalsky Apr 23 '18 at 16:54
14

Your approach should work. The issue you're encountering is your use of this in your onchange event is invalid. Try replacing your this.form references with something like this:

<%= Html.DropDownList(
        "ddl", ViewData["AvailableList"] as SelectList, 
        new { onchange = @"
            var form = document.forms[0]; 
            form.action='MyMethod';
            form.submit();" 
        } ) %>
Jacob
  • 77,566
  • 24
  • 149
  • 228
6

This is a jQuery thing. Give it a class and wire up to it.

Html.DropDownList("ddl", AvailableList, new { @class = "_select_change" })

A rough script might look like this:

$('._select_change').change(function() { $.post(ctrlUrl); })
mtmk
  • 6,176
  • 27
  • 32
2

Like both : D

I propose a mix -I like a lot the jQuery.

$('ddl').change(
 function() {
  // This contains your selected option val
  $(this).val();

// so you can do domething like...
  $.post(
    $(this).val(),
    { Param1: xxxx,
      Param2: xxxx,
      Param3: xxxx },
    function(data) {
     // handle your call here. 'data' contains the response
    } );
}
SDReyes
  • 9,798
  • 16
  • 53
  • 92
2

From the controller action, you're going to make the call the same way:

<%= Html.DropDownList(ddl, ViewData["items"] as SelectList, new { onchange = string.format("doSomething({0}); return false;", action) }) %>

Once you do that, put a Javascript function on your page that calls the method. How you call it, however, is going to depend on whether it's an AJAX call or not. That is, whether you want a page round-trip or not. For the non-AJAX call:

function doSomething(action) {
    window.location.href = action;
}

If it's an AJAX call:

function doSomething(action) {
    $.load(action);
}

To pass parameters to the action, you just need to make sure that all of the data elements you want to pass are contained within the <form> tag. For example, let's say you want to include a first and last name with your drop down list. In the view, you'll do something like this:

<%= using (Html.BeginForm()) 
   { %>
    <table>
        <tr>
            <td>First Name:</td>
            <td><%= Html.TextBox("FirstName") %></td>
        </tr>
        <tr>
            <td>Last Name:</td>
            <td><%= Html.TextBox("LastName") %></td>
        </tr>
        <tr>
            <td>Assign to:</td>
            <td><%= Html.DropDownList(ddl, ViewData["items"] as SelectList, 
                new { onchange = string.format("doSomething({0}); return false;", ViewData["action"]) }) %></td>
        <tr>
    </table>
<% } %>

In the Javascript function:

function doSomething(action) {
    var firstName = $('#FirstName').val();
    var lastName = $('#LastName').val();
    $.load(action, { first: firstName, last: lastName });
}
Neil T.
  • 3,308
  • 1
  • 25
  • 30
2

@Shimmy is there a way to do this as a one-liner, without defining the function in js?

yes you can and here is the code for that:

@Html.DropDownListFor(m => m.Name, new SelectList((System.Collections.IEnumerable)ViewBag.DropDownName, "Value", "Text"), new { @class = "form-control", onchange = "document.location.href = '/Home/Employee?c=' + this.options[this.selectedIndex].value;" })
Nick Kahn
  • 19,652
  • 91
  • 275
  • 406
-1
@Html.DropDownListFor(model => model.StudentId, new SelectList(ViewBag.List, "Value", "Text"), new { @class = "form-control", @style = "width:65px", onchange = "document.location.href = '/Student/find?Id=' + this.options[this.selectedIndex].value;" })
  • 2
    Would be helpful if you could also explain your code – Hasan Sefa Ozalp May 20 '20 at 04:35
  • 1
    Hi, welcome to Stack Overflow! When you answer a question you should include some kind of explanation, like what the author did wrong and what you did to fix it. I'm telling you this because your answer has been flagged as low-quality and is currently being reviewed. You can [edit] your answer by clicking the "Edit" button. – Federico Grandi May 20 '20 at 06:54
  • I concur with Nick Kahn's solution. I pasted my own working code as confirmation. – Leon Polyakov May 20 '20 at 15:29