Make Ajax call before page loads - ajax

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.

Related

MVC Core ajax and return result is a view

MVC Core, NET 5, not razor pages.
On a view I have three select components (bootstrap-select). I populate them via ViewModel.
"Get request -> Controller -> return View(viewModel);"
What I want...
When I changed value in any select component I do a post request (ajax) to the same controller (other method) and return view with repopulated data.
"'Post request -> Controller -> return View(changedModel);"
As I understood when I did ajax request I should handle it result in success and other cases.
What I should to do to reload page with new data?
Is it possible to achive this with this approach?
Yes, this is possible and you do not need to reload the page, just append the returned html to wherever you want it.
$.ajax({
type: "POST",
url: {your_url},
dataType: "html",
success: function (html) {
$("#someDiv").html(html);
}
});
What I should to do to reload page with new data?
If the post action return the same view as the get action and you want to reload the whole page, I think there is no need to use ajax. You can just redirect to post action with a form submission. If the view returned by the post action is a partialview you want render to the current view, you can use it like that in #cwalvoort answer.
Based on advices of cwalvoort and mj1313
I did:
Render main page with partials. ViewModel transfered to a partial as a parameter
On main page I added eventListners to controls with JS.
When control changes - ajax request to backend happens Controller/GetPartialView
Result from ajax replace html in partial section
Programmatically show needed components, re-add eventListners
PS Really need to learn Blazor or UI Framework :)
Code samples:
// JS
document.addEventListener("DOMContentLoaded", function (event) {
BindSelectActions();
});
function BindSelectActions() {
$('#selectGroups').on('hidden.bs.select', DoPartialUpdate);
$('#selectCompanies').on('hidden.bs.select', DoPartialUpdate);
$('#selectPeriods').on('hidden.bs.select', DoPartialUpdate);
}
function DoPartialUpdate(e, clickedIndex, isSelected, previousValue) {
// ToDo: Implement common script with "CallBackend" function
$.ajax({
type: "POST",
url: 'https://localhost:44352/TestController/TestGetPartial',
// no data its a stub at the moment
// data: $('#form').serialize(),
success: function (data, textStatus) {
$("#testControls").html(data);
$('#selectGroups').selectpicker('show');
$('#selectCompanies').selectpicker('show');
$('#selectPeriods').selectpicker('show');
BindSelectActions();
}
});
}
// Controllers
[HttpGet]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
public async Task<IActionResult> Main()
{
// ViewModel = _helper -> _mediator -> query -> context
return await Task.Run(() => View(new TestViewModel()));
}
[HttpPost]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
public IActionResult TestGetPartial(TestViewModel model)
{
// ViewModel = _helper -> _mediator -> query -> context
var result = new TestViewModel();
result.IsPageReload = "yes";
result.TestCollection = new string[] { "A", "B", "C" };
result.Companies = new List<SelectListItem> { new SelectListItem { Value = "999",
Text = "Test" } };
// ModelState.Clear();
return PartialView("_TestPartial", result);
}
// Main and partial views
#model TestViewModel
#{
ViewData["Title"] = "Test";
}
<div id="testControls">
#await Html.PartialAsync("_TestPartial", Model)
</div>
#section Scripts {
<script type="text/javascript" src="~/js/test.js" asp-append-version="true">
</script>
}
#model TestViewModel
<form>
<div class="d-flex flex-row justify-content-between mt-4">
<div><select id="selectGroups" asp-for="Groups" asp-items="Model.Groups"
class="selectpicker" data-live-search="true" data-style="btn-outline-dark"
title="Group"></select></div>
<div><select id="selectCompanies" asp-for="Companies" asp-items="Model.Companies"
class="selectpicker" data-live-search="true" data-style="btn-outline-dark"
title="Company"></select></div>
<div><select id="selectPeriods" asp-for="Periods" asp-items="Model.Periods"
class="selectpicker" data-live-search="true" data-style="btn-outline-dark"
title="Period"></select></div>
<div><button type="button" class="btn btn-outline-dark">Import</button></div>
</div>
</form>
<div>
#{
if (null != Model.TestCollection)
{
foreach (var item in Model.TestCollection)
{
<p>#item</p>
<br>
}
}
}
</div>

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.

ASP.NET MVC partial view refresh on button click

I'm using VS 2013, MVC 5.
Here is the content of my partial view (_Sales.cshtml):
#model IEnumerable<SomeModel>
<div id="outer">
<div id="inner1">
#(Html.Kendo().Chart<SomeModel>(Model)
...
)
</div>
<div id="inner2">
<table>
<tr>
<td>Total Sales </td>
<td>#Model.First().TotalSales.ToString("C")</td>
</tr>
<tr>
<td>Total Discount </td>
<td>#Model.First().TotalDiscount.ToString("C")</td>
</tr>
</table>
</div>
</div>
Below is an action method used while loading first time:
public ActionResult _Sales()
{
IEnumerable<SomeModel> salesList = null;
SearchCriteriaObject criteria = null;
salesList = getting data as list;
return PartialView(salesList);
}
So far, all work fine as expected. That's my partial view is rendering fine with initial data.
Now my requirement is I need to refresh my partial view as user specify search criteria and hit search button.
Here is the search button specific action method:
public ActionResult Get_BulletChartData_Updated(SearchViewModel criteriaModel)
{
IEnumerable<SomeModel> salesList = null;
SearchObject criteria = new SearchObject();
if (ModelState.IsValid)
{
if (criteriaModel != null)
{
//populating criteria here
}
salesList = //Getting data in list format
}
return PartialView(salesList);
}
On search button click event handler in javascript, I do this:
$("#btnSearch").click(function () {
...
var Url = $('#Url').val(); //Getting action method url from hidden field
$.ajax({
type: "POST",
dataType: 'HTML',
data: JSON.stringify(SearchViewModel),
url: Url, //#Url.Action("Get_SalesDataFiltered", "Sales")
contentType: "application/json; charset=utf-8",
success: function (result)
{
alert('success');
//$("#outer").load(result);
},
error: function ()
{
alert("error");
}
});
On search button click, I always get error alert message.
Could you please guide me the correct way to achieve this.
I'm new to MVC. Please feel free to ask for more info.
If you provide me with code, it'd be great.
Thanks.
I think that your problem is that you post a json object, while your post method has as a parameter a SearchViewModel object.
I believe that If you change this
data: JSON.stringify(SearchViewModel)
to this
data: $("#yourFormId").serialize()
you will get the expected result.

Spring controller - send html as response

I have a loaded jsp page with products and addtocart link against it. I am trying to show the cart in a div in the same page. I want to send html as response. This is what i have done. It just returns the string <div>output</div>. Can someone show me how i should do it.
Controller
#RequestMapping(value="/addtocart{id}", produces = "text/plain;charset=UTF-8")
#ResponseBody
public String addToCart(#PathVariable("id") int id, #ModelAttribute("cart") Cart cart,Model model)
{
Product product = productService.getProductById(id);
if (product != null) {
CartLine line = new CartLine();
line.setProduct(product);
line.setQuantity(1);
productService.updateProduct(product);
}
return "<div>output</div>";
}
JSP
<td><a id="demo4" href="addtocart${product.id}">Add To Cart</a> </td>
$('#demo4').click(function() {
$.ajax({
url : '/addtocart{id}',
dataType: 'json',
contentType: "text/html",
type : 'GET',
data :{id:id},
success : function(response) {
$('#output').html(response);
}
});
});
<div id="output" style="display:none">
<h2>Cart Content(s):</h2>
</div>
I also favor the approach with using the view, and separate page even on ajax call. Nevertheless what you're asking is possible, simply change your produces = "text/plain;charset=UTF-8" to produces
produces = "text/html;charset=UTF-8"
There are many other aspects that appear wrong, not related to Spring MVC, so even with the produces corrected you still have to do few corrections to get what you're expecting.
I think that you're not sending an ajax call at all. You're most likely doing a complete browser redirect. When first read, I was confused that "text/plain" vs "text/html" makes a difference in an ajax response, but now I believe that you're actually redirecting via browser. Change this <a id="demo4" href="addtocart${product.id}">Add To Cart</a> into something like this <a id="demo4" href="#">Add To Cart</a> and add return false to the end of your function. This will execute the function, and the return will make sure that the link is not followed
When you do this you'll notice a few issues with your ajax call as well; firstly, url : '/addtocart{id}' should be url : '/addtocart${product.id}
Capture your response in complete function not in success, and get the output as response.responseText, the response will return fine, but the browser will attempt to parse it as json and fail.
Your div will remain invisible, you should add some js to toggle that
One Spring MVC gotcha, your Cart bean seems to have a property called id as well. Because of this, your id path variable should be renamed, otherwise it'll be ignored
This would be something that, if not completly, than much closer to working
<a id="demo4" href="#">Add To Cart</a>
<div id="output"></div>
<script>
$('#demo4').click(function() {
$.ajax({
url : '/addtocart${product.id}',
dataType: 'json',
contentType: "text/html",
type : 'GET',
data :{id:4},
complete: function(response) {
$('#output').html(response.responseText);
}
});
return false;
});
</script>
Renaming PathVariable
#RequestMapping(value="/addtocart{productId}", produces = "text/plain;charset=UTF-8")
public String addToCart(#PathVariable("productId") int productId, #ModelAttribute("cart") Cart cart,Model model)
You can do it with AJAX and still return a separate page for your Card, as Slava suggested.
JSP page cart.jsp:
<%# page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!-- custom html for your cart representation, just an example -->
<div>
<h1>${cart.headline}</h1>
<p>${cart.otherProperty}</p>
</div>
Controller:
#RequestMapping(value="/addtocart{id}")
public String addToCart(#PathVariable("id") int id, #ModelAttribute("cart") Cart cart, Model model) {
doSomethingWithCart(cart);
model.addAttribute("cart", cart); // add cart to model after doing some custom operations
return "cart"; // resolved to cart.jsp by your view resolver
}
This way you are using AJAX but still you are returning dynamic html content (
adjusted to one specific cart).

MVC correct handling of ajax search form and paging

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.

Resources