Wait to run Javascript after all partials are loaded on a page - c#

The application I'm working on is an internal business application for managers. It's a C# web application. The main office has an instance of this app running and it always has the latest version. Each store has it's own instance of the application running as well, but may not always have the latest version. A manager logs in to the main office app and then selects a store to view. That store's instance is pulled up in the main part of the app, the upper menu bar is from the main office's instance. Thus, it is possible that the main office has v1.8 and a store to have v1.7.
There are some features in 1.8 that show up on the menu bar that are not present in 1.7 that I would like to hide. The main page has multiple partials that get loaded and the very last partial has the specific store's version number that is determined by the code on that store's server. Because of this, the only way to get the version number is to get it after it is rendered on the page. The main problem I'm having is that the Javascript I'm using to hide the links to the new features is running before the partial with the version number loads.
I need the Javascript to wait until the entire page finishes loading to execute the hiding code. Also, the application is only run in Chrome.
Here is the code I've got to hide the links:
$(window).load(function () {
if ($('.version').length !== 0) {
if (parseFloat($('.version').text().slice(5)) > 1.7) {
$('.analysis').show();
} else {
$('.analysis').hide();
}
}
});

If you are loading the partial with ajax on the client side explicitly, you can just add a complete function to call:
$( "#storeContainer" ).load( "url/for/partial", function () {
if ($('.version').length !== 0) {
if (parseFloat($('.version').text().slice(5)) > 1.7) {
$('.analysis').show();
} else {
$('.analysis').hide();
}
}
});
Of course, you'll probably want the "url/for/partial" to use #Url.Content or #Url.Action if you can.
If you are using The Ajax Helper, you can set the OnSuccess property of your AjaxOptions to call you back:
#Ajax.ActionLink("Refresh",
"Store",
new AjaxOptions {
HttpMethod = "POST",
UpdateTargetId = "storeContainer",
InsertionMode = InsertionMode.Replace,
OnSuccess = "updateSuccess" });
where you have defined your OnSuccess function in javascript:
var updateSuccess = function () {
if ($('.version').length !== 0) {
if (parseFloat($('.version').text().slice(5)) > 1.7) {
$('.analysis').show();
} else {
$('.analysis').hide();
}
}
There are some other ideas about how to include the script in your partial view or call it during your ajax success event on How to initialize jquery ui widgets that may be loaded dynamically in MVC3 application
If you were using Asp.net AJAX, you could use Sys.Application.add_load(function(){...}).

Have you tried using
$(document).on("ready", function() {
});
in place of $window.load()?

Related

ASP.Net Core MVC - FullCalendar - Events are not displayed

Using FullCalendar 5.11.3 in my ASP.Net Core MVC application I have a problem that events aren't displayed.
On debugging one can see that on calendar initialization the controllers action is correctly called and also the data that is returned is correct and follows the requirements (https://fullcalendar.io/docs/event-source-object)
JSON that is returned when accessing action directly
[{"id":1,"title":"Beata Kowal","start":"13-09-2022","allDay":true}]
Calendar is placed in a partial view (as in the code below) and used in home view (in the future I plan to use it in several views with different data sources).
<script>
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'dayGridMonth',
events: {
url: '/Home/GetCalendarData',
success: function() {
alert("ok");
},
failure: function() {
alert("error");
}
}
});
calendar.render();
});
</script>
<div class="row">
<div id='calendar' />
</div>
In the HomeController there is an action responsible for getting data to be used for displaying events
// GET: Home/GetCalendarData
public JsonResult GetCalendarData()
{
List<Appointment> appointments = _context.Appointments
.Include(app => app.Employee)
.Include(app => app.Customer)
.ToList();
List<HomeIndexGetViewModel> appointmentsIndexViewModel = _mapper.Map<List<Appointment>, List<HomeIndexGetViewModel>>(appointments);
return new JsonResult(appointmentsIndexViewModel);
}
Calendar is rendering and the alert on success is also displayed. What is more in the developer mode there are no errors or warnings. Yet, events still don't display.
My initial guess:
It takes too long to fetch data from the database and before action returns its result calendar is rendered and events can't not longer be added. If so, then how can I change it to work in a desired way? Introduce JS callback?
The problem was with parsing the date. It was not capable to process the provided date format which was "dd-MM-yyyy". After changing to "yyyy-MM-dd HH:mm:ss" everything works fine and events are displayed correctly.

ASP.NET MVC controller method called via getJson not working on server

Obligatory "This works in my dev environment, but doesn't work on the server."
I have an ASP.NET 5 MVC project, using .NET Core, in which actions taken on a certain view trigger a "getJson" call in my javascript code, which in turn calls a function on the controller to obtain data from the server, in order to update the page without a postback.
When a valid entry is made in a textbox, this function is called in my javascript:
function getCustomerOptions(cn) {
$.getJSON('/Home/GetBillingCustomerByCustNum', { cust: cn }, function (data) {
// handle returned json data
}
}
... which calls function GetBillingCustomerByCustNum in my Home controller:
public async Task<JsonResult> GetBillingCustomerByCustNum(string cust)
{
var data = //[retrieve data from server thru repository function]
return Json(data);
}
In my dev environment, this works great. But after I publish the application to an IIS environment on a Windows Server 2016 machine, this fails. It seems that IIS is trying to call '/Home/GetBillingCustomerByCustNum' as though it were a view or a physical object, and so returns a 404 error.
I have tried altering my getJson controller call -- jquery function "getCustomerOptions" -- by adding
<%= Url.Content("~/") %>
so that the call becomes
$.getJSON('<%= Url.Content("~/") %>/Home/GetBillingCustomerByCustNum', { cust: cn }, function (data) { ...
but that still fails. According to the debugger console, the above url is being translated as
http://localhost/HC_RFQ/Home/%3C%=%20Url.Content(%22~/%22)%20%%3E/Home/GetBillingCustomerByCustNum?cust=[given value]
The only other step I could find suggested I prepare my url with an HTML helper, like so:
var url = '#Url.Content("~/Home/GetBillingCustomerByCustNum/")'
$.getJSON(url, { cust: cn }, function (data) {...
but of course that fails because HTML helpers don't work in separate javascript files. Var url is passed in as literally written.
Finally, I know this is not a case of my javascript files not being linked properly, because I can breakpoint my javascript in the debugger ahead of this failing call, and the breakpoints are hit at runtime.
What else can I try to fix this? Any advice is appreciated.
Have you tried a simple Home/GetBillingCustomerByCustNum, just without the starting /? From how you describe the error in production, that's basically a server issue when composing the final route to the controller.
Dropping the Home/ part works because you're calling that action from a view that resides on the same controller's folder path. Since you're using .NET Core, I suggest using the asp-action and asp-controller tag helpers as they let the server decide what's the actual route to the desired methods, even if you're POSTing or GETing without an actual postbacks. For example, this is what I do using javascript to call my methods on a form:
<form asp-controller="myController" asp-action="myAction">
and this is how I get my js code to retrive the corresponding url
let form = $(this).parents('form')[0];
let url = form.getAttribute('action');
the form doesn't have an actual submit button, so that the calls are all made from javascript.

Problems with jquery request to reload partial view in C# MVC

I have been searching for a solution this problem for quite some time, including browsing the message board here. To start off, I will refer to an existing post:
I have used the most popular solution, and the controller successfully runs the query:
[HttpGet]
public ActionResult LoadBidders(int Id)
{
List<tblWinLossBidderMap> bidders = _context.tblWinLossBidderMaps.Where(p => p.WinLossID == Id).ToList();
return PartialView("_WinLossBidderView", bidders);
}
The Javascript
$(document).ready(function () {
$("#pY").on("click", function () {
var temp = $("#WinLossID").val();
$.ajax({
url: "/WinLoss/LoadBidders",
type: "GET",
data: { Id: temp }
})
.done(function(partialViewResult) {
$("#BidderCompany").html(partialViewResult);
});
});
});
The problem I have is that when the controller exits, back into the Javascript, I get an exception "Microsoft.CSharp.RuntimeBinder.RuntimeBinderException", "Cannot convert null to 'bool' because it is a non-nullable type value".
Note that the partial view uses a foreach to display the data. Ideally, once this is working, I will take the code snippet and append it after another jquery function that actually adds to this list. The effect is the user would fill in part of a larger form (like master/detail), click a button, a record would be added, and then this routine would update the partial view with the updated information. I doubt this part is important, but just including it for completeness.
Is there some something missing from my code?
Note that I am using Visual Studio 2015.

Getting AJAX to not load a new page after submitting a form and instead render a partial view or nothing

I'm in a bit of a bind here, I am trying to submit a form using ajax, all goes well and dandy until after the server has done it's thing, it decides to load to the action onto a new page, which is exactly what I do not want.
Here is my controller
[HttpPost]
public ActionResult Submit(int id, string trainingProgramId, FormCollection form, User user)
{
//Do Some action
return null;
}
In a different controller I have it set up to do $return PartialView(model);
this is the JQuery code that I am using.
$(function () {
$("form").submit(function (e) {
if (nextquestion()) { //check if posting can proceed
$.ajax({
type: "POST",
data: $(this).serialize(),
url: $(this).attr("action"),
success: function (response) {
alert(response);
$('#cases:last-child').insertAfter(response);
},
error: function (data) { }
});
}
e.preventDefault();
});
});
In all cases I am being redirected to a different url after performing the operation. Which is not the intention, especially if my intention might be to load more stuff into the page.
I've been tring everything, a bunch of solutions, but once my controller does a return statement the page automatically reloads to $/Submit
I have added $ #Scripts.Render("https://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.unobtrusive-ajax.min.js"); to my scripts
From any other example I am finding this should work as I want it to, by remaining on the same page, however I am finding it difficult to understand who is responsible for changing the page either way. When I return my PartialView, a completely new page loads with the model as I've had it set up for the Partial View to be inserted originally.
Anyone care to explain what is going on or why my code is wrong?
I can't find it after a whole day of trying to debug.

With asp.net mvc, what can we put in AjaxOptions OnSuccess etc?

I don't seem to be able to reference items in the DOM using jquery.
How can I show/hide an element during a OnBegin/OnSuccess event?
How about add/remove a css class?
You're probably using something like:
<% using(Ajax.BeginForm("UpdateForm", new AjaxOptions{ OnBegin = "showIt", OnSuccess = "hideIt" })) { %>
...
<% } %>
OnBegin and OnSuccess are names of globally visible javascript functions that will be called at respected Ajax request stage. Those functions should do what you require:
function showIt() {
// show and add a class on the same element
$("#SomeElementID").show().addClass("some-class");
}
function hideIt() {
// hide and remove class on the same element
$("#SomeElementID").hide().removeClass("some-class");
}
I'm not sure about function parameters, because:
I've never used this functionality - I only use HtmlHelper extension methods and write custom jQuery scripts that do Ajax requests and all that handling; one of the bad parts from my point of view are those global functions that are usually better avoided if not explicitly needed; I also suspect that a rare minority does Asp.net MVC Ajax apps this way, they usually use HtmlHelper extensions and use jQuery to manually control Ajax processing.
Microsoft documentation is very scarce and doesn't talk about function parameters (or call context for that matter)
Instead of using global functions you can write anonymous functions inline (which isn't good because everything gets crammed ina single line as a string but supposedly works):
... OnBegin = "function() { $(\"#SomeElementID\").show().addClass(\"some-class\"); }" ...
So tell me if it works.
Hide Something:
$.ajax( //whatever
success: function() { $('.classToShow').show(); }
)
Remove Class:
$.ajax( //whatever
success: function() { $('#hideSomething').removeClass('aClass'); }
//addClass to add
)
OnBegin?
Did you mean beforeSend
$.ajax( //whatever
beforeSend: function() { $('#hideSomething').removeClass('aClass'); }
//addClass to add
)
Are you sure your referencing jquery and not msajax?

Categories