1

For some reason, when I press any of the buttons of my view, all properties of the model passed to the action method are null:

View:

@using (Html.BeginForm("FolderChange", "EdiSender", FormMethod.Post, new {id = "ediFilesForm"}))
{
    var directoriesSelectList = new SelectList(Model.Directories);
    @Html.DropDownListFor(m => m.SelectedDirectory, directoriesSelectList, new {@Id = "Directories", @style = "width:Auto;", @size = 20, onchange = "$('#ediFilesForm').submit()", name = "action:FolderChange"})

    var ediFilesSelectList = new SelectList(Model.EdiFileNames);
    @Html.DropDownListFor(m => m.SelectedEdiFile, ediFilesSelectList, new {@Id = "EdiFileNames", @style = "width:Auto;", @size = 20})
}

<br/>
...

<form action="" method="post">
    <input type="submit" value="Send" name="action:Send" />
    <input type="submit" value="Delete" name="action:Delete" />
    <input type="submit" value="Refresh" name="action:Refresh" />
</form>

Controller:

    [HttpPost]
    [MultipleButton(Name = "action", Argument = "Send")]
    public ActionResult Send(EdiFileModel ediFileModel)
    {
           ....
    }

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultipleButtonAttribute : ActionNameSelectorAttribute
{
    public string Name { get; set; }
    public string Argument { get; set; }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        var isValidName = false;
        var keyValue = string.Format("{0}:{1}", Name, Argument);
        var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);

        if (value != null)
        {
            controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
            isValidName = true;
        }

        return isValidName;
    }
}

It used to work when my buttons were within the Html.BeginForm() block, but I cannot have it like that anymore, because it has now action name as FolderChange(), which is different from e.g. Send() or other action method that handles button press.

Thanks.

EDITED:

@section scripts
{
    <sctipt type="text/javascript">
    $("#Directories").change(function () {
        var selectedDirectory = $("#Directories").val();   

        $(function () {
            $.getJSON('/DoWork/FolderChangeAjaxCall?selectedDirectory=' + selectedDirectory, function (result) {
                var ddl = $('#EdiFileNames');
                ddl.empty();
                $(result).each(function () {
                    $(document.createElement('option'))
                .attr('value', this.Id)
                .text(this.Value)
                .appendTo(ddl);
                });
            });
        });
    });    
    </sctipt>
}

<h2>Existing EDI Files</h2>
@using (Html.BeginForm("FolderChange", "EdiSender", FormMethod.Post, new {id = "ediFilesForm"}))
{
    var directoriesSelectList = new SelectList(Model.Directories);
    @Html.DropDownListFor(m => m.SelectedDirectory, directoriesSelectList, new {@Id = "Directories", @style = "width:Auto;", @size = 20})

    var ediFilesSelectList = new SelectList(Model.EdiFileNames);
    @Html.DropDownListFor(m => m.SelectedEdiFile, ediFilesSelectList, new {@Id = "EdiFileNames", @style = "width:Auto;", @size = 20})
David Shochet
  • 5,035
  • 11
  • 57
  • 105
  • 1
    You answered your own question, you said it used it to work when your buttons were in the form. Now they are outside the form and have know idea what your model or your model's properties are. You can have submit buttons in 1 form, and in the controller method you can determine which was clicked – CSharper May 29 '14 at 16:07
  • @C Sharper I know I can have buttons in one form, but the dropdown above didn't work when the buttons were in the same form, as I needed to specify in Html.BeginForm() action name specific for the dropdown. If I did not specify the action name, the controller could not distinguish between buttons and the dropdown. – David Shochet May 29 '14 at 16:36
  • Idk sounds like your making a little complicated, have you thought about using an Ajax call on ddl change instead of submitting the form? – CSharper May 29 '14 at 17:15
  • @C Sharper Unfortunately, I don't know yet how to do it. – David Shochet May 29 '14 at 17:24
  • Ok so lets run down the scenario, you post to the controller after every dropdownlist change correct? So I guess it is going to a method named `FolderChange` what are you doing inside that. Are you simply trying to get the ddl selected value, then what – CSharper May 29 '14 at 18:08
  • @C Sharper On changing the folder, the second dropdown box is populated with names of the files that are in the selected folder. Then if I press e.g. the Send button, the selected file is sent. – David Shochet May 29 '14 at 18:11
  • Ok so your doing a cascading dropdownlist, you can find plenty of examples doing that. I'll try to work something out. I would definitely read up on using Ajax calls for your MVC projects. They will be needed everywhere – CSharper May 29 '14 at 18:20

1 Answers1

1

Here it is, it's probably way off from what you thought the answer would be, but it will cascade the dropdowns. Your going to have to substitute your values and context in, but it will work. Now you can place your buttons in the form and not have to have the dropdown's submit the form, which is pretty poor design anyways.

@Html.DropDownListFor(x => x.ddlID, Model.myDDLList, new { id = "ddl" }) 

@Html.DropDownListFor(x => x.myDDLList2, Model.myDDLList2, new { id = "foo" }) 

Script

$("#ddl").change(function () {

        var Id = $("#ddl").val(); //1st dropdown Value        

        $(function () {
            $.getJSON('/DoWork/AjaxCall?Id=' + Id, function (result) {
                var ddl = $('#foo');
                ddl.empty();
                $(result).each(function () {
                    $(document.createElement('option'))
                .attr('value', this.Field1)
                .text(this.Field2)
                .appendTo(ddl);
                });
            });
        });
    });

Controller

public ActionResult AjaxCall(int Id)
    {
        using (PerformanceEntities context = new PerformanceEntities())
        {             
            return this.Json(
                  (from obj in context.ACCOUNT.Where(x => x.ACCT_ID == Id).ToList() 
                   select new
                   { 
                       Field1 = obj.ACCT_ID,
                       Field2 = obj.ACCT_NAME 
                   }),
                  JsonRequestBehavior.AllowGet
               );
        }         
    }

You can check out this post for reference

Community
  • 1
  • 1
CSharper
  • 5,420
  • 6
  • 28
  • 54
  • @C Sharper Thanks. I tried it, but for some reason the contents of the script is displayed on the page... What am I doing wrong? I added my code to the original question. BTW, I don't use Id and Value in the dropdown, the directories and file names are unique. – David Shochet May 30 '14 at 12:56
  • 1
    it's showing up on the page probably because you closed your script like this `` lol. I'm not sure but you might have to supply a field for the text and value field of the dropdown – CSharper May 30 '14 at 13:02
  • @C Sharper Yes, I misspelled it. The execution doesn't come to the FolderChangeAjaxCall() though... – David Shochet May 30 '14 at 13:08
  • 1
    Be careful, you copy and pasted my code and didn't change it for your situation. Look here `'/DoWork/FolderChangeAjaxCall?selectedDirectory` your trying to call a controller called `DoWork`. Likewise inside your each function where you have this.id/this.value...you have to change Id and Value to what you would like, I'll edit to show that you can define whatever field you want – CSharper May 30 '14 at 13:10
  • @C Sharper Oh, I did not realize it was controller name. I made it work using just "this" instead of "this.Value" or "this.Id". Thanks. Is it possible to automatically select the first item in the second dropdown on first dropdown selection change? – David Shochet May 30 '14 at 13:58
  • @ C Sharper Nothing is selected when I change selection in the first dropdown. – David Shochet May 30 '14 at 14:12
  • 1
    Depending on which version of JQuery it is one of the following `$("select#foo").prop('selectedIndex', 0);` `$("select#foo").attr('selectedIndex', 0);` – CSharper May 30 '14 at 14:15
  • @C Sharper Works! Thanks! BTW, I guess I should do the same for my buttons? – David Shochet May 30 '14 at 14:21
  • Do what for the buttons? There's no selected index for a button – CSharper May 30 '14 at 14:22
  • @C Sharper I meant AJAX. – David Shochet May 30 '14 at 14:27
  • No do don't that. Put your buttons back in the form so they cause the form to post – CSharper May 30 '14 at 14:35
  • Thank you very much for everything. – David Shochet May 30 '14 at 14:36
  • this could be useful http://stackoverflow.com/questions/5922175/jquery-getjson-vs-ajax-json, Bohzo has a good answer. Your going to be using `$.ajax` a lot in MVC – CSharper May 30 '14 at 14:42