Reputation: 99
I'm very new to MVC and I'm trying to figure out if there is a better way to do this. I have a textbox for the user to put in their search, then based on that search I am displaying some results below said search box. I am trying to avoid having so much code logic in my view and would like to know if there is a better way of handling this. Here is my existing code, where based on what the value of "Model.Results" is it will return one of 3 partial views or a button if the rest of my logic passes:
@section CustomerPrefixInfo
{
@if (Model.Results == PrefixSearch.SearchResults.CustomerFound)
{
@Html.Partial("_CustomerPrefixInfo")
}
@if (Model.Results == PrefixSearch.SearchResults.PrefixResultsFound)
{
@Html.Partial("_PrefixResults")
}
@if (Model.Results == PrefixSearch.SearchResults.AnimalsFound)
{
@Html.Partial("_AnimalSearchResults")
}
@if (Model.Results == PrefixSearch.SearchResults.ValidNewPrefix)
{
using (Html.BeginForm("Index", "PrefixManagement", new { prefix = Model.AnimalPrefix.Prefix, dbPrefix = Model.AnimalPrefix.DbPrefix }))
{
<fieldset>
<input id="btnReservePrefix" type="submit" value="Reserve Prefix" />
</fieldset>
}
}
}
I would like to put this inside a controller so that it just returns the view that is to be displayed, then just display that view on the page. Aftering doing some rearch I thought using Ajax.BeginForm with the InsertionMode set to InsertAfter would do the trick:
@using (Ajax.BeginForm("GenericSearch", "Home", FormMethod.Post, new AjaxOptions { InsertionMode = InsertionMode.InsertAfter, UpdateTargetId = "searchResults" }))
{
<fieldset>
<input id="btnPrefixSearch" type="submit" value="Prefix Search/Validate"/>
@Html.EditorFor(model => model.Input)
</fieldset>
<div id="searchResults">
</div>
}
My GenericSearch Action then uses a switch to decide which partial view to return:
public ActionResult GenericSearch(PrefixSearch prefixSearch)
{
//some database logic here to get the results
switch (prefixSearch.Results)
{
case PrefixSearch.SearchResults.CustomerFound:
return PartialView("_CustomerPrefixInfo", prefixSearch);
case PrefixSearch.SearchResults.PrefixResultsFound:
return PartialView("_PrefixResults", prefixSearch);
case PrefixSearch.SearchResults.AnimalsFound:
return PartialView("_AnimalSearchResults", prefixSearch);
default:
return null;
}
}
But when I tried this it puts the partial view on a new page.
here is one of my partial views (they are all 3 mostly identical to this)
@model MVC_Test_Project.Models.PrefixSearch
@{
ViewBag.Title = "PrefixResults";
}
@{
Layout = null;
}
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.PrefixResults[0].Prefix)
</th>
<th>
@Html.DisplayNameFor(model => model.PrefixResults[0].CustomerCount)
</th>
<th>
@Html.DisplayNameFor(model => model.PrefixResults[0].Link)
</th>
</tr>
@foreach (var item in Model.PrefixResults)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Prefix)
</td>
<td>
@Html.DisplayFor(modelItem => item.CustomerCount)
</td>
<td>
<a href="@item.Link">edit</a>
</td>
</tr>
}
</table>
Any help would be appreciated!
Edit Just a helpful hint in case anybody makes the same stupid mistake I did, make sure your bundles are called before your scripts.
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/bundles/bootstrap")
<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.min.js"></script>
I had added in those last 2 lines when it was mentioned to use those, but they were above my bundles....and thus the ajax didn't work because of it. Thanks for everybodies help, all is well now! --Joseph
Upvotes: 5
Views: 358
Reputation: 3180
Make sure you are including jQuery and jquery.unobtrusive-ajax.js
(or jquery.unobtrusive-ajax.min.js
) at the top of your page you want to perform the Ajax on.
Like this:
<script src="~/scripts/jquery-1.x.x.js" />
<script src="~/scripts/jquery.unobtrusive-ajax.js" />
...
The rest of your page down here
...
This allows the Partial's postback to be rendered in-page, rather than re-directing you each time.
If you haven't got the jQuery files, or are unsure how to include them; have a read here: http://www.c-sharpcorner.com/UploadFile/4fcb5a/update-a-div-and-partial-view-using-ajax-beginform-on-form-s/ - it's very useful.
Ensure that Unobtrusive JS is enabled, in your web.config file, also. They look like this in the <appsettings>
node:
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
If you are using validation - which I doubt you are for a search; but stay with me - you may also want to include jquery.validate.js
and jquery.validate.unobtrusive.js
, too. This can allow client-side validation (where possible) making the UX a lot smoother.
NOTE: There are other ways of doing the Ajax request; such as creating it in your own JS script - this example is the easiest using an already-available and much-loved library :)
Hope this helps!
EDIT
The switch
on which Partial view to return can then be done solely from inside your Controller. You can remove the logic from within the page view.
The Ajax will then take care of replacing the content of the div's ID you gave to the Ajax.BeginForm
helper.
You could either replace the search form entirely - by using its ID, or, better still - place an empty <div>
container within the page, ready to display the results in:
<div id="searchResults"></div>
The Ajax will then return the Partial view and put the content inside your searchResults
div.
EDIT 2
I noticed in your Ajax.BeginForm
's AjaxOptions
object you are missing HttpMethod = "POST"
.
The AjaxOptions
should look something like this:
new AjaxOptions {
HttpMethod = "POST",
UpdateTargetId = "searchResults",
InsertionMode = InsertionMode.Replace
}
Upvotes: 2
Reputation: 54646
I would like to put this inside a controller so that it just returns the view
Seems pretty straight forward:
ViewModel:
public class MyModel
{
public string PageToRender { get; set; }
}
Controller Action
public ActionResult DoLogic()
{
//var Results = ?? as The ENum
switch(Results)
{
PrefixSearch.SearchResults.CustomerFound:
model.PageToRender = "_CustomerPrefixInfo";
// etc etc
}
return View(model);
}
View:
@{if (!string.IsNullOrEmpty(model.PageToRender))
Html.RenderPartial(model.PageToRender);}
Although I would probably decorate the Enum:
public enum SearchResults
{
[Display(Name="_CustomerPrefixInfo")]
CustomerFound
}
And then there is no switch statement, you just grab the enum value display attribute's name value.
Upvotes: 2