MVC correct handling of ajax search form and paging - ajax

I have a question regarding the ajax and simple filtering. Before writing this post i did read some question more or less regarding this topic, but it is not the same and i didn't receive my answere there!
I have a simple search page, with only few filtering, this filtering should not immidiately be adjustaed to the results or whatever. So when the user changes the filters and click search he gets the result, when he modifies filter nothing should happen until he clicks search again.
So my question is more about handling with the paging, i know how the paging works on the server side with .Skip() .Take() however when i click on the page number, i still have to do an ajax call and submit the same model back just with other page number, but the paging is outside of the form and it doesn't have submit stuff on it ... so how do i resubmit the model back with all the filteres in there?
So here is my view:
#using (Ajax.BeginForm("Index", "Search", new AjaxOptions { UpdateTargetId = "searchResults" }, new { #role = "form", #class = "form-horizontal" }))
{
#Html.AntiForgeryToken();
#Html.EditorFor(m => m.IsOnline)
#Html.EditorFor(m => m.UserLocation)
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">#Base.Search</button>
</div>
</div>
}
And the paging is:
#if(Model.TotalPages>1)
{
<div class="row">
<div class="col-sm-12 col-centered">
<ul class="pagination text-center">
<li class="disabled">«</li>
#{
for(int i = 1; i<=Model.TotalPages; i++)
{
<li><a href="#">#i
#if(Model.CurrentPage==i)
{
<span class='sr-only'>(current)</span>
}
</a></li>
}
}
<li>»</li>
</ul>
</div>
</div>
}
And here is my controller:
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Index(SearchModel searchModel)
{
if (ModelState.IsValid)
{
searchModel = Operations.GetSearchedListUsers(searchModel);
}
return View(searchModel);
}
So how i see it, even when i click on the page number i should do an index post action and re submit model but for example with other pagenumber how should i do it?
Or is my thinking is totaly wrong and in first place i shouldn't use ajax.form and model??
Please give advice?

Lets start with a general search page.
In search page we will a SearchPage view which have partial view SearchResult view which also may have another paging controls
SearchPage view will have all the control Filter that will keep the states if search, searchResult view update when Search Button is click. To maintain the filter,search keyword and page number and other states we would need to override the default submit and handle all through the ajax calls.
SearchResult view is partial view which will be updated on the searchbutton or Page click.
We might need to create searchModel model that has all the requires attributes:Filters,keyword and Page.
To make everything in ease, we would handle all these secenario in a single action called
Search with SearchModel. The searchModel will return a partialView("SearchResult").
Regarding the ajax call, lets say we have
var keyword=$("#txtKeyword").val();
var filter1=$("#txtFilter11").val();
function SubmitSearch() {
$.ajax({
url: '/Home/Search',
type: 'POST',
data: { keyword: keyword, Filter1: filter1}
timeout: 50000,
success: function (data) {
//Process data
},
error: function (x, t, m) {
if (t === "timeout") {
alert("got timeout");
} else {
alert(t);
}
}
});
}
And you can hook in the search button, page button etc.

Related

Call Controller Method Which Return View With Ajax Call From Asp.net MVC View Page

i'm using .Net core 2.1 application, inside for loop how can i trigger controller view page without returning to ajax response,
see following code
this is my razor view
#foreach (var item in Model.CategoryList)
{
<div class="col-sm-6 col-md-4 mb-4 mb-lg-0 col-lg-2" onclick="SelectCategory(#item.CategoryId)">
<a href="#" class="popular-category h-100">
<span class="icon"><span class="#item.Icon"></span></span>
<span class="caption mb-2 d-block">#item.CategoryName</span>
<span class="number">32,891</span>
</a>
</div>
}
<script>
function SelectCategory(id) {
$.ajax({
type: 'POST',
url: '#Url.Action("ProductsList","Home")',
dataType: 'json',
data: { parentId: id }
});
}
</script>
public ActionResult ProductsList(int parentId)
{
List<PilCategory> all = new List<PilCategory>();
if(parentId > 0)
all = _context.PilCategory.Where(x=>x.ParentId == parentId).OrderBy(a => a.ParentId).ToList();
else
all = _context.PilCategory.OrderBy(a => a.ParentId).ToList();
return View(all);
}
pls someone help me, thaks for advance
how can i trigger controller view page without returning to ajax response
As far as I know, we couldn't trigger controller view page without returning to ajax response. Since the ajax will send the request to the controller view and the controller view will return the view as html response back to the ajax.
If we don't handle the response, that means current page will not change.
If you just want to pass the parentId to the ProductsList method, I suggest you could try to use window.location, this will make this page redirect to the ProductsList view which achieve refresh the whole page.
Notice: If we using ajax to call ProductsList, the whole page will not refresh. If we using window.location, it will redirect to another page or refresh the whole page.
More details about how to achieve this, you could refer to below codes:
#section Scripts{
<script>
function SelectCategory(id) {
location.href = "/Home/ProductsList?parentId=" + id;
}
</script>
}
If you want to use ajax to achieve this, I suggest you could try to handle the response by using ajax success method. Normally, we will return the partial view in controller method and then we could add it into the html page by using jquery without refreshing the page.
More details about how to achieve this, you could refer to this answer.

partial views to get data and then post the results to save in database

I am very new to MVC, let me try to explain my scenario in plain simple English:
I have an strongly typed mvc form/page (Product.cshtml) with a model, say ProductViewModel.
This page has got two search buttons, one to search and bring the items to be added to the Product and other to bring in the location, most probably partial views.
Now, what I want is that these search results work in ajax form without complete post back, and then the results of these searches (items and location) should be posted back using model binding to the form when user clicks on the submit button.
What could be the best way of achieving this functionality?
Immediate responses will be well appreciated.
I thought, its good to share the complete code for clarity:
I have one form(Service1.chtml) that has a partial view to display users(_TestUser a partial view:read only), then another partial view(_PlotServiceRequestData) that should have a field to search the plot and bring back the details lke its owner name and landuser etc.
Then when I click on submit button of the main form, I should be able to read all data(main form) + new data from _PlotServiceRequestData partial view and save all data to database.
I was trying one more option, that is, to use #Ajax.ActionLink on Service1.cshtml to call the _GetPlotDetails method and then store partial view data in TempData, so that it is available to the form when users clicks on "Submit" button of Service1.cshtml, is this a right approach?, if I use ajax.BeginForm inside partial view then the data is posted to the
Service1 controller method which is actually to save the form data and not to update the partialview and in this method even I am not getting model data of the partial view.
Sevice1.cshtml:
#model ViewModels.TestViewModel
#{
ViewBag.Title =
"Service1";
}
#
using (Html.BeginForm())
{
#Html.LabelFor(m => m.Title)
#Html.EditorFor(m => m.Title)
#Html.Partial(
"_TestUser", Model)
<div id="RequestPlotData">
#Html.Partial(
"_PlotServiceRequestData", Model.requestData)
</div>
<button type="submit">Save Form</button>
}
#section Scripts {
}
_PlotServiceRequestData.cshtml:
===============================
#model ViewModels.PlotServicesRequestDataViewModel
<
div id="RequestPlotData">
#
using (Ajax.BeginForm("_GetPlotDetails", "Test", new AjaxOptions { UpdateTargetId = "RequestPlotData", Url = Url.Action("_GetPlotDetails","Test") }))
{
<h1>Request Details</h1>
 
<div>
#Html.LabelFor(m => m.plotAddress)
#Html.EditorFor(m => m.plotAddress)
<input type="submit" name="submit" value="Ajax Post" />
</div>
<div>
#Html.LabelFor(m => m.LandUser)
#Html.EditorFor(m => m.LandUser)
</div>
<div>
#Html.LabelFor(m => m.OwnerName)
#Html.EditorFor(m => m.OwnerName)
</div>
}
</
div>
CONTROLLER:
==========
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.Mvc;
namespace
TestNameSpace
{
public class TestController : Controller
{
//
// GET: /Test/
public ActionResult Service1()
{
Injazat.AM.mServices.
LocalDBEntities context = new Injazat.AM.mServices.LocalDBEntities();
TestViewModel model =
new TestViewModel() { user = context.Users.First(), Title = "Land Setting Out",
requestData =
new PlotServicesRequestDataViewModel() { ServiceNumber ="122345", TransactionDate="10/10/2033" } };
return View(model);
}
[
HttpPost()]
public ActionResult Service1(TestViewModel model)
{
PlotServicesRequestDataViewModel s = (PlotServicesRequestDataViewModel)TempData[
"Data"];
TestViewModel vm =
new TestViewModel() { user = model.user, requestData = s, Title = model.Title };
return View(vm);
 
}
[
HttpGet()]
//public PartialViewResult _GetPlotDetails(string add)
public PartialViewResult _GetPlotDetails(PlotServicesRequestDataViewModel requestData)
{
//PlotServicesRequestDataViewModel requestData = new PlotServicesRequestDataViewModel() { plotAddress = add};
requestData.OwnerName =
"owner";
requestData.LandUser =
"landuser";
TempData[
"Data"] = requestData;
return PartialView("_PlotServiceRequestData", requestData);
}
}
}
You can probably use the jQuery Form plugin for this. This makes the process of posting the data from your form back to the server very easy. The form would post to an action that would return a partial view that you can then push into your UI.
To make this easier, jQuery form actually has a "target" option where it will automatically update with the server response (ie. the partial view returned from your search action).
View
<form id="searchForm" action="#(Url.Action("Search"))" method="POST">
<input name="query" type="text" /> <!-- order use Html.TextBoxFor() here -->
<input type="submit" />
</form>
<div id="result"><!--result here--></div>
Javascript
$('#searchForm').ajaxForm({
target: '#result'
});
Controller
public ActionResult Search(string query)
{
// Do something with query
var model = GetSearchResults(query);
return Partial("SearchResults", model)
}
This should hopefully help you to get on the right track. jQuery Form is a good plugin and is the main thing you should look into for ajaxifying your form posts back to the server. You might also want to look into using jQuery's $.post and $.ajax functions, but these require slightly more work.

Make Ajax call before page loads

Before the page loads, I need to run a check on the user's security level. This will determine which elements of our nav bar they are able to see. I have tried two methods at running this ajax call, both inside the $(document).ready function.
(the div named container encompasses the ul in the html below)
$(document).ready(function ($) {
//First attempt
$('#container').load(
$.ajax({
type: 'GET',
url: '#Url.Action("CheckSecurity","Home")'
})
);
//Second attempt
window.onload = function () {
$.ajax({
type: 'GET',
url: '#Url.Action("CheckSecurity","Home")'
});
};
});
Since this is an ASP MVC 3 site, I've set a breakpoint in the CheckSecurity method. I can tell neither call is working due to the fact it is never fired.
The controller method is listed below
public ActionResult CheckSecurity()
{
ViewBag.UserName = Security.GetUserName(User);
ViewBag.Admin = Security.IsAdmin(User);
ViewBag.ITsupport = Security.IsItSupport(User);
ViewBag.Read = Security.IsViewer(User);
ViewBag.Modify = Security.IsModifier(User);
return View();
}
This is supposed to check the user's security level, place the boolean value in the ViewBag, and then determine whether or not to display the Admin Features drop down item below
<li class="dropdown">
<a href="#"
class="dropdown-toggle"
data-toggle="dropdown"
data-hover="dropdown">
Admin
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li>#Html.MenuLink("Products", "Index", "Product")</li>
<li>#Html.MenuLink("Product Training", "Index", "Course")</li>
<li>#Html.MenuLink("Continuing Ed", "Index", "ContEdCourse")</li>
#if (ViewBag.Admin)
{
<li>#Html.MenuLink("Admin Features", "Index", "DropDownValues")</li>
}
</ul>
</li>
When the page attempts to load, it instead crashes with this error pointing to the #if (ViewBag.Admin) line:
Cannot convert null to 'bool' because it is a non-nullable value type
Any help/suggestions greatly appreciated. Thx!
/ViewBags just work in the same View. Which means this:
If you are in
public ActionResult Index()
{
ViewBag.Index
}
and then you execute by ajax
public ActionResult OtherAction()
{
ViewBag.Other
}
The ViewBag.Other will not be visible in Index
public ActionResult Index()
{
ViewBag.Index
ViewBag.Other//erro other is null cuz because bellows to OtherAction view
}
So, you could return a list instead.

Update partial view after edit

I have the following index:
<div id='addProduct'>
#{ Html.RenderPartial("Create", new BoringStore.Models.Product()); }
</div>
<div id='productList'>
#{ Html.RenderPartial("ProductListControl", Model.Products); }
</div>
The partial Create view contains an invisible div which is used to create a new product.
After doing so the partial view ProductListControl is updated.
Now I want to do so with an edit function.
Problem: It's not possible to integrate the edit page while loading the index because at this moment I don't know which product the user wants to edit.
My thought:
I'd like to call my existing edit view in an jquery modal (not the problem) so the user can perform changes.
After saving the modal is closed (still not the problem- I could handle this) and the ProductListControl is updated (here's my problem ... :().
How am I able to do so?
I've seen some tutorials but I'd like to keep it as clean & easy as possible.
Most of them are using dom manipulating and get feedback from the server (controller) by a JsonResult.
If possible I'd like to stick to the razor syntax, no pure JavaScript or jquery and if possible I'd like to avoid JsonResults.
One way might be to use the Ajax.BeginForm for your create product view.
The Ajax.BeginForm accepts a number of AjaxOptions, one being the UpdateTargetId (your DOM id, in this case your productlist div), more info here.
Then in your product controller code you can return a partial view, with the product list. So for example:
Index.cshtml
#using (Ajax.BeginForm("AjaxSave", "Product", new AjaxOptions { HttpMethod = "GET", UpdateTargetId = "productList", InsertionMode = InsertionMode.Replace }))
{
// your form
<p>
<input type="submit" value="Save" />
</p>
}
...
<div id="productList">...
</div>
ProductController.cs
[HttpGet]
public ActionResult AjaxSave(Product product)
{
if (ModelState.IsValid)
{
// save products etc..
}
var allProducts = _productService.GetAllProducts();
return PartialView("ProductListControl", allProducts);
}
There is a nice article on about this here.

Partial View - >> How to REFRESH the HTML content without having to redirect to the view

My site has a concept like Skype that allow users to go "Online" and "Offline". I created a partial view that allows the user to switch mode:
#if (Convert.ToBoolean(ViewData["IsLogged"].ToString()))
{
<div id="onlineStatus">
You are currently <strong>ONLINE</strong> >>
#Html.ActionLink("Go OFFLINE", "GoOffline", "Account")
</div>
}
else
{
<div id="offlineStatus">
Ready for business >>
#Html.ActionLink("Go ONLINE", "GoOnline", "Account")
</div>
}
This is how we load the Partial View:
public ActionResult OnlineStatusCtrl()
{
if (SiteUser.IsAuthenticated)
ViewData["IsLogged"] = SiteUser.IsOnline.ToString();
return PartialView("OnlineStatusCtrl");
}
When a user clicks on the link "Go ONLINE" or "Go OFFLINE", the Controller respond as:
public ActionResult GoOnline()
{
if (SiteUser.IsAuthenticated)
SiteUser.GoOnline();
ViewData["IsLogged"] = "True";
return RedirectToAction("Index", "Home");
//return PartialView("OnlineStatusCtrl");
//return EmptyResult();
}
public ActionResult GoOffline()
{
if (SiteUser.IsAuthenticated)
SiteUser.GoOffline(true);
ViewData["IsLogged"] = "False";
return RedirectToAction("Index", "Home");
}
This works well ...but the ONLY problem is that if I am on View XXXX, and I click on "Go Online", the controller redirects me to the Index View.
I tried "return EmptyResult()" or "return PartialView("OnlineStatusCtrl") but it does just not work.
From the code, you can see that the only thing the PartialView cares about is the "ViewData['IsLogged'] value"
QUESTION:
What is the way to REFRESH a partial view without having to refresh the entire page or redirect to the main page?
Is it maybe a matter of putting an Html.Beginform() ?
Is it maybe a matter of the Controller returning something that just refresh the content of the PartialView independently from what view is holding the PV itself?
Aiaiaiaia
I still can't figure out how MVC works with PartialViews/
UPDATE
I have updated the code as x suggested and the HTML output is as follow:
<div id="divStatus">
<form action="/" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#divStatus" id="form0" method="post">
<div id="offlineStatus">
Ready for business >>
Go Online
</div>
</form>
</div>
When I click on the LINK, the Controller return PartialView("_OnlineStatusCtrl"); which is hte name of the calling PV ...and the ENTIRE PAGE gets replaced.
You're going to have to use an ajax call of some sort (Microsoft ajax helpers built into MVC, or jquery/javascript ajax call.
To use Microsoft's Ajax, you can use Ajax.BeginForm or Ajax.ActionLink. Both take an AjaxOptions parameter that will allow you to set javascript functions for OnSuccess, and an UpdateTargetId to display the returned data (usually a partial view). Using this will call your action which should return a partial view. Your partial view then replaces the html element (usually a div) identified by the UpdateTargetId parameter. If you decide to go this route, make sure you reference all the proper Microsoft ajax/mvc scripts. You'll pretty much need each script with any combinations of Microsoft, Ajax, Mvc, and even unobtrusive in the name.
Here's an example of one of my ajax forms (modified slightly for simplicity)
<% using(Ajax.BeginForm("addAttribute", new { id = Model.PersonId, attributeId = item.AttributeId }, new AjaxOptions { UpdateTargetId = "myTargetId", OnSuccess = "initForm" })) { %>
<input type="submit" value="Ok" class="editMode okButton" disabled="disabled" />
<input type="button" class="editMode cancelButton" value="Cancel" />
<br />
<input type="button" value="Add" class="addButton" />
<% } %>
I have a div with an id of "myTargetId" (for this example) that will be updated with the returned partial view.

Resources