9
votes

I have a partial view called Search.cshtml that I display in /Home/Index. In this file, I have an HTML form that searches and pulls back /Views/Accounts/Index with the search results. I want to display those results in the modal popup div that is in the Search view.

When I Click the Search (sumbit input) in the code below I get an empty modal.

I am still a novice when it comes to MVC. I tried a few different results I found on Stack Overflow, but I haven't been able to find the resolution. The code below at least gives me a modal pop up, although it is blank.

Am I missing something insanely simple? I have tried everything in the modal-body below (Html.Action, RenderAction, Partial, RenderPartial) and nothing seems to work. Also, am I barking up the wrong tree there?

I have a couple screenshots and the code below.

/Home/Index with Search partial view

Empty Search Modal

Search.cshtml

@model CustomerRelationshipManager.Models.Search

@{ViewBag.Title = "Search";}
@using (Html.BeginForm("Index", "Accounts", new { id = "searchForm" }))
{

<div style="border: solid 1px #ccc; padding: 30px 0 30px 30px; border-radius: 5px;
    width: 325px; margin: auto; display: table;">
    <table>
        <tr>
            <td valign="top">
                Search By:
            </td>
            <td>
                @Html.DropDownList("Search_Type", "Search_Type")
            </td>
        </tr>
        <tr>
            <td valign="top"></td>
            <td>
                @Html.TextBox("Search_String")
            </td>
        </tr>
        <tr>
            <td></td>
            <td>
                <input type="submit" data-toggle="modal" data-target="#myModal" value="Search" />
            </td>
        </tr>
    </table>
</div>

<div class="modal fade" id="myModal">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title">Modal title</h4>
            </div>
            <div class="modal-body">
                @{Html.Action("Index","Accounts");}
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary">Save changes</button>
            </div>
        </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

}

HomeController.cs

    public ActionResult Search()
    {
        List<SelectListItem> items = new List<SelectListItem>();
        items.Add(new SelectListItem() { Text = "Account Number", Value = "Account_ID" });
        items.Add(new SelectListItem() { Text = "Last Name", Value = "Last_Name" });
        items.Add(new SelectListItem() { Text = "Phone Number", Value = "Phone_Number" });
        ViewBag.Search_Type = items;
        return PartialView();
    }

    [HttpPost]
    [AllowAnonymous]
    public ActionResult Search(Search search)
    {

        return PartialView("~/Accounts/Index");
        //return RedirectToAction("Index", "Accounts");
    }

AccountController.cs (I want to call Index() from this Controller)

public ActionResult Index(string Search_Type, string Search_String)
    {
        if (Search_String == null)
        {
            var accounts = db.Accounts
                .Include(a => a.Account_Type)
                .Include(a => a.Account_Person)
                .Include(a => a.Account_Address)
                .Include(a => a.Account_Contact);
            return PartialView(accounts.ToList());
        }
        else
        {
            if (Search_Type == "Account_ID")
            {
                var accounts = db.Accounts
                .Include(a => a.Account_Type)
                .Include(a => a.Account_Person)
                .Include(a => a.Account_Address)
                .Include(a => a.Account_Contact)
                .Where(a => a.Account_ID.ToString() == Search_String);
                return PartialView(accounts.ToList());
            }
            else if (Search_Type == "Last_Name")
            {
                var accounts = db.Accounts
                .Include(a => a.Account_Type)
                .Include(a => a.Account_Person)
                .Where(b => b.Account_Person.Any(c => c.Person.Last_Name.StartsWith(Search_String)))
                .Include(a => a.Account_Contact)
                .Include(a => a.Account_Address);
                return PartialView(accounts.ToList());
            }
            else if (Search_Type == "Phone_Number")
            {
                var accounts = db.Accounts
                .Include(a => a.Account_Type)
                .Include(a => a.Account_Person)
                .Include(a => a.Account_Contact)
                .Where(b => b.Account_Contact.Any(c => c.Contact.Value == Search_String && c.Contact.Contact_Type.Name.Contains("Phone")))
                .Include(a => a.Account_Address);
                return PartialView(accounts.ToList());
            }
            else
            {
                var accounts = db.Accounts
                    .Include(a => a.Account_Type)
                    .Include(a => a.Account_Person)
                    .Include(a => a.Account_Address)
                    .Include(a => a.Account_Contact);
                return PartialView(accounts.ToList());
            }
        }

Account Index.cshtml (I want to display this in the modal popup)

@model IEnumerable<CustomerRelationshipManager.Models.Account>

@{
ViewBag.Title = "Home";
}

<h2>Index</h2>

<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
    <th>Account #</th>
    <th>Contact Name(s)</th>
    <th>Address</th>
    <th>Contact</th>
</tr>
w2
@foreach (var item in Model)
{
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Account_ID)
            <span>&nbsp;</span>
        </td>
        <td>
            @foreach (var i in item.Account_Person)
            {
                <span>
                    <b>@Html.DisplayFor(x => i.Person_Type.Name)</b>
                    <br />
                    @Html.DisplayFor(x => i.Person.First_Name)
                    &nbsp;
                    @Html.DisplayFor(x => i.Person.Last_Name)
                </span>
                <br />
            }
        </td>
        <td>
            @foreach (var i in item.Account_Address)
            {
                <span>
                    <b>@Html.DisplayFor(x => i.Address_Type.Name)</b>
                    <br />
                    @Html.DisplayFor(x => i.Address.Address1)
                    <br />
                    @Html.DisplayFor(x => i.Address.Address2)
                    @if (i.Address.Address2 != null)
                    { <br />}
                    @Html.DisplayFor(x => i.Address.City)
                    &nbsp;
                    @Html.DisplayFor(x => i.Address.State)
                    &nbsp;
                    @Html.DisplayFor(x => i.Address.Postal_Code)
                    <br />
                    @Html.DisplayFor(x => i.Address.Country)
                    <br />
                </span>
            }
        </td>
        <td>
            @foreach (var i in item.Account_Contact)
            {
                <span>
                    <b>@Html.DisplayFor(x => i.Contact.Contact_Type.Name)</b>
                    <br />
                    @Html.DisplayFor(x => i.Contact.Value)
                    <br />
                </span>

            }

        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id = item.Account_ID }) |
            @Html.ActionLink("Details", "Details", new { id = item.Account_ID }) |
            @Html.ActionLink("Delete", "Delete", new { id = item.Account_ID })
        </td>
    </tr>
}

2
If your submit button is inside the form tag, clicking on that will do a form submit. You need to make an ajax call to the action method to get the partial view result and update the modal content.Shyju

2 Answers

9
votes

With your current code, when user clicks on the submit button, it will do a normal form submit as your submit button is inside a form tag. For your use case, you should be hijacking that normal form submit event using javascript and make an ajax call to your action method where it will use the search_type and search_string parameters to get the filtered data and return a partial view result. This partial view result is the HTML markup you want to display inside the modal dialog. Once your ajax call receives the response from server, update the modal dialog's body content with this response and fire the modal dialog.

@using (Html.BeginForm("Index", "Accounts", FormMethod.Post, new { id = "searchForm" }))
{
    <div>
        <input type="text" name="Search_String" />
        <input type="submit" id="submit" value="Search" />
    </div>
}    
<div class="modal fade" id="myModal">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" 
                                      data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title">Modal title</h4>
            </div>
            <div class="modal-body">
            </div>
            <div class="modal-footer">
                <button type="button" class="btn" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary">Save changes</button>
            </div>
        </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

Now have some javascript code, which listen to the submit event on your search form and make stop the normal behavior (normal form submit) and instead do an ajax form submit.

$(document).ready(function () {

    $('#searchForm').submit(function (e) {
        e.preventDefault();
        var $form = $(this);

        $.post($form.attr("action"), $form.serialize()).done(function (res) {
            $mymodal = $("#myModal");
            //update the modal's body with the response received
            $mymodal.find("div.modal-body").html(res);
            // Show the modal
            $mymodal.modal("show");
        });
    });

});

Now you have to make sure that your Index action method returns a partial view (so that it will not execute any layout code, but just that view code).

[HttpPost]
public ActionResult Index(string Search_Type, string Search_String)
{
    // Your existing filtering code goes here.
    return PartialView(accounts.ToList());
}
1
votes

I figured it out!

  1. I moved the modal outside of the HTML.BeginForm in the Search.cshtml. Then, I simplified the input on the form and removed the data-toggle and data-target properties.

    @model CustomerRelationshipManager.Models.Search
    
    @{
      ViewBag.Title = "Search";
    }
    @using (Html.BeginForm("Index", "Accounts", FormMethod.Post, new { id = "searchForm" }))
    {
    
    <div style="border: solid 1px #ccc; padding: 30px 0 30px 30px; border-radius: 5px;
    width: 325px; margin: auto; display: table;">
        <table>
        <tr>
            <td valign="top">
                Search By:
            </td>
            <td>
                @Html.DropDownList("Search_Type", "Search_Type")
            </td>
        </tr>
        <tr>
            <td valign="top"></td>
            <td>
                @Html.TextBox("Search_String")
            </td>
        </tr>
        <tr>
            <td></td>
            <td>
                <input type="submit" id="submit" value="Search" />
            </td>
        </tr>
    </table>
    </div>
    }
    <div class="modal fade" id="myModal">
        <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title">Modal</h4>
            </div>
            <div class="modal-body">
    
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary">Save changes</button>
            </div>
        </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
    

  2. I moved the javascript to the bottom of the _layout.cshtml shared file.

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
    
    <script type="text/javascript">
    $(document).ready(function () {            
        $('#searchForm').submit(function (e) {
            e.preventDefault();
            var $form = $(this);
            $.post($form.attr("action"), $form.serialize()).done(function (res) {
                $mymodal = $("#myModal");
                //update the modal's body with the response received
                $mymodal.find("div.modal-body").html(res);
                // Show the modal
                $mymodal.modal("show");
            });
        });
    
       });
    
  3. After figuring that out, I had a LINQ error that I discovered by setting a breakpoint in the Index() function of my AccountsController. Once I fixed that, the Index() Action in my AccountsController Appeared in my Modal Popup.

HomeController Search() Modal Dialog Displaying AccountsController Index()

Thanks for your help, Shyju!