我有一个 DNN 模块,它将使用 Lightslider 构建产品轮播。
当页面加载时,从我们的 ERP 服务器数据库中获取 10 个产品需要几秒钟。在加载时,当我尝试导航到另一个页面时,它不会重定向,直到 Ajax 查询返回数据。它会等到产品加载完毕,然后它会重定向到我大约 5 秒前点击的链接。
我已启用 async: true 并尝试将异步添加到服务器端代码,但没有运气。
$(document).ready(function () {
GetCarouselProductData();
});
async function GetCarouselProductData() {
var CarouselModID = "<%=CarouselModID%>";
var CarouselMode = "<%=CarouselMode%>";
var CarouselURL = $.fn.GetBaseURL() + 'DesktopModules/PRandomProductCarousel/API/RandomProductCarousel/GetRandomCarouselProductsSQLAsync?ModID=' + CarouselModID;
if (CarouselMode == 'SpecificSKU') {
CarouselURL = $.fn.GetBaseURL() + 'DesktopModules/PRandomProductCarousel/API/RandomProductCarousel/GetSpecificSKUCarouselProductsAsync?ModID=' + CarouselModID;
}
await $.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
cache: false,
url: CarouselURL,
datatype: "json",
async: true,
success: function (data) {
var counter = 0;
var VatText = "<%=IncTaxText%>";
var DetailedLinkRedirect = "<%=DetailedPageLink%>/sku/";
if (data.length > 0) {
var source = "";
$.map(data, function (item) {
var ImageSRC;
if (item.ProductImages.length > 0) {
ImageSRC = item.ProductImages[0].ProductThumbUrl
} else {
ImageSRC = '/DesktopModules/RandomProductCarousel/Images/no_image.png';
}
var alphabet = (counter + 10).toString(36);
var TitleDescription = item.Title;
if (TitleDescription.length > 70) {
var NewTitle = TitleDescription.substr(0, 70);
NewTitle = NewTitle.substr(0, NewTitle.lastIndexOf(" ")) + '...';
} else {
var NewTitle = TitleDescription;
}
var StockCode = item.StockCode.trim();
var FinalRedirectLink = DetailedLinkRedirect + StockCode;
source += "<li class=\"item-" + alphabet +"\">"+
"<div class='box'>"+
"<!--image box-------->"+
"<div class='slide-img'>"+
"<img src='" + ImageSRC + "' alt='" + item.Title + "' />"+
"<!--overlay-->"+
"<div class='overlay-carousel'>"+
"<!--buy btn---->" +
"<div class='overlay-inner-carousel-btn-positioning'><a href='javascript:void(0);' class='carousel-quote-btn' onclick=\"addQuoteWithOnClickFunction('" + item.StockCode + "', 1, '" + item.CustomerPriceInclVat + "');\">Add to Quotes</a></div>" +
"<div class='overlay-inner-carousel-btn-positioning'><a href='javascript:void(0);' class='carousel-buy-btn' onclick=\"addProductWithOnClickFunction('" + item.StockCode + "', 1, '" + item.CustomerPriceInclVat + "');\"><%=CartButtonText%> </a></div>" +
"<div class='overlay-inner-carousel-btn-positioning'>" +
"<a href='" + FinalRedirectLink + "' class='carousel-view-btn'>View</a>" +
"</div>" +
"</div>"+
"</div>"+
"<!--Detail box-->"+
"<div class='detail-box'>"+
"<!--type-->"+
"<div class='type'>"+
"<a href='" + DetailedLinkRedirect + item.StockCode + "'>" + NewTitle +"</a>"+
"</div>"+
"<!--price-->" +
"<div class='CarouselStockCode'>" +
"<span class='carousel-stock'>" + StockCode + "</span>" +
"</div>" +
"<span class='price'>" + item.CustomerPriceInclVat + " " + VatText + "</span>" +
"</div>"+
"</div>"+
"</li>";
counter++;
return source;
});
$("#autoWidth2").remove();
$(".lSSlideOuter").remove();
$(".responsive-product-carousel").remove();
$(".responsive-product-carousel2").append(source);
}
},
error: function (xhr, ajaxOptions, thrownError) {
$.fancybox.open(xhr.responseText);
}
}).promise().done(function () {
$(document).ready(function () {
//ZR - 29/01/2021 - Mode that determines if it should auto slide
var SliderMode = "<%=AutoSlideSetting%>";
if (SliderMode == "False") {
SliderMode = false;
} else {
SliderMode = true;
}
//ZR - 29/01/2021 - Sets the loop mode of the slider
var LoopMode = "<%=LoopSliderSetting%>";
if (LoopMode == "False") {
LoopMode = false;
} else {
LoopMode = true;
}
var SliderPauseTime = <%=SliderPausePeriod%>;
// website for settings sachinchoolur.github.io/lightslider/settings.html
$('#autoWidth').lightSlider({
autoWidth: true,
loop: LoopMode,
adaptiveHeight: true,
pauseOnHover: true,
auto: SliderMode,
pause: SliderPauseTime,
onSliderLoad: function () {
$('#autoWidth').removeClass('cS-hidden');
}
});
ViewCarouselProductLoading();
});
});
在 Controller 的服务器端,我尝试使用以下两种方式获取数据,但似乎没有区别。
没有异步代码的控制器代码(测试 1):
/// <summary>
/// Get Random Product Information via SQL
/// </summary>
/// <returns></returns>
/// <remarks>ZR 25/01/2021</remarks>
[AllowAnonymous]
[HttpGet]
public object GetRandomCarouselProductsSQLAsync(int ModID)
{
try
{
AmountOfRandomProductsToFetch = TryGetPortalSetting("AmountOfRandomProductsToLoad_" + ModID);
return GetRandomProductsFromSQL(Int32.Parse(AmountOfRandomProductsToFetch));
}
catch (Exception ex)
{
EventLogController logController = new EventLogController();
logController.AddLog("Could not retreive random products for the Product Carousel via SQL.", ex.ToString(), EventLogController.EventLogType.ADMIN_ALERT);
throw;
}
}
带有异步代码的控制器代码(测试 2):
/// <summary>
/// Get Random Product Information via SQL
/// </summary>
/// <returns></returns>
/// <remarks>ZR 25/01/2021</remarks>
[AllowAnonymous]
[HttpGet]
public async System.Threading.Tasks.Task<object> GetRandomCarouselProductsSQLAsync(int ModID)
{
try
{
return await GetRandomProductsSQLAsync(ModID);
}
catch (Exception ex)
{
EventLogController logController = new EventLogController();
logController.AddLog("Could not retreive random products for the Product Carousel via SQL.", ex.ToString(), EventLogController.EventLogType.ADMIN_ALERT);
throw;
}
}
public async System.Threading.Tasks.Task<object> GetRandomProductsSQLAsync(int ModID)
{
try
{
AmountOfRandomProductsToFetch = TryGetPortalSetting("AmountOfRandomProductsToLoad_" + ModID);
return GetRandomProductsFromSQL(Int32.Parse(AmountOfRandomProductsToFetch));
}
catch (Exception ex)
{
EventLogController logController = new EventLogController();
logController.AddLog("Could not retreive random products for the Product Carousel via SQL.", ex.ToString(), EventLogController.EventLogType.ADMIN_ALERT);
throw;
}
}
我什至尝试使用“Then”以不同的方式进行 Ajax 调用,但没有运气。
$(window).load(function () {
console.log("window is loaded");
doAjaxGet()
.then(json => {
console.log('json: ', json);
processJSONData(json);
})
});
async function doAjaxGet() {
var CarouselModID = "<%=CarouselModID%>";
var CarouselMode = "<%=CarouselMode%>";
var CarouselURL = $.fn.GetBaseURL() + 'DesktopModules/PRandomProductCarousel/API/RandomProductCarousel/GetRandomCarouselProductsSQLAsync?ModID=' + CarouselModID;
if (CarouselMode == 'SpecificSKU') {
CarouselURL = $.fn.GetBaseURL() + 'DesktopModules/PRandomProductCarousel/API/RandomProductCarousel/GetSpecificSKUCarouselProductsAsync?ModID=' + CarouselModID;
}
const result = await $.ajax({
url: CarouselURL,
crossDomain: true,
async: true,
type: 'GET',
});
return result;
}
function processJSONData(data) {
// NOTE: data is already parsed
$.map(data, function (item) {
console.log('Data: ', item.Title);
});
}
更新
我已将前端代码更改为使用普通的 XMLHttpRequest 而不是 JQuery Ajax。我在下面有两个视频来展示它到底在做什么以及下面的 Javascript Ajax 代码。
视频 1(构建产品轮播)
https://www.youtube.com/watch?v=n637FGv3e9U
视频 2(仅将产品标题记录到控制台日志)
https://www.youtube.com/watch?v=8mHNcgBoe-Q
Javascript Ajax 代码:
$(document).ready(function () {
JavascriptCarouselFetch();
});
function JavascriptCarouselFetch() {
var CarouselModID = "<%=CarouselModID%>";
var CarouselURL = $.fn.GetBaseURL() + 'DesktopModules/ParrotRandomProductCarousel/API/RandomProductCarousel/GetRandomCarouselProductsSQLAsync?ModID=' + CarouselModID;
var http = new XMLHttpRequest();
http.open("GET", CarouselURL, true);
http.send();
http.onreadystatechange = function () {
if (http.readyState == 4 && http.status == 200) {
$.map(JSON.parse(http.response), function (item) {
console.log("Data: " + item.Title);
})
}
};
控制器代码:
/// <summary>
/// Get Random Product Information via SQL
/// </summary>
/// <returns></returns>
/// <remarks>ZR 25/01/2021</remarks>
[AllowAnonymous]
[HttpGet]
public async System.Threading.Tasks.Task<object> GetRandomCarouselProductsSQLAsync(int ModID)
{
try
{
AmountOfRandomProductsToFetch = TryGetPortalSetting("AmountOfRandomProductsToLoad_" + ModID);
return GetRandomProductsFromSQL(Int32.Parse(AmountOfRandomProductsToFetch));
}
catch (Exception ex)
{
EventLogController logController = new EventLogController();
logController.AddLog("Could not retreive random products for the Product Carousel via SQL.", ex.ToString(), EventLogController.EventLogType.ADMIN_ALERT);
throw;
}
}
/// <summary>
/// Gets Random Products from SQL
/// </summary>
/// <param name="ProdCode"></param>
/// ZR 25/01/2021</remarks>
public object GetRandomProductsFromSQL(int AmountOfRandomProductsToFetch)
{
try
{
if (AmountOfRandomProductsToFetch > 0)
{
int pid = PortalController.Instance.GetCurrentPortalSettings().PortalId;
if (SessionManager.GSettings == null) SessionManager.GSettings = new ParrotDNNCommon.Components.GlobalSettings(pid);
var portalCtrl = new ParrotDNNCommon.Controllers.ParrotPortalSettingsController();
var parrotPortalController = new ParrotPortalSettingsController();
var currSettings = parrotPortalController.GetPortalSettings(pid);
return m_Product.GetRandomProductWebDetailsFromSQL(SessionManager.GSettings.Globalvars, pid, AmountOfRandomProductsToFetch, currSettings.PricingModeIsShowRRPOnly);
}
return null;
}
catch (Exception exc)
{
throw;
}
}
普通类
/// <summary>
/// Get the product details
/// </summary>
/// <param name="GV">Global Variables</param>
/// <param name="WebPortalId">Web Portal ID</param>
/// <param name="Count">Amount of random products to return</param>
/// <param name="ShowRRPOnly">Boolean to determine if RRP should only show or not</param>
/// <returns>WebProductDetails</returns>
/// <remarks>ZR - 25/01/2021</remarks>
public List<CommonDataDefinitions.Products.WebProductDetails> GetRandomProductWebDetailsFromSQL(CommonLibrary.Globalvars GV, int WebPortalId, int Count, bool ShowRRPOnly)
{
List<CommonDataDefinitions.Products.WebProductDetails> result = new List<CommonDataDefinitions.Products.WebProductDetails>();
try
{
result = GV.ClHelper.eBusiness.GetRandomProductWebDetails(WebPortalId, SessionManager.CurrentUserInfo.CustomerCode, ShowRRPOnly, Count, SessionManager.CurrentUserInfo.ParrotUserId);
}
catch (Exception ex)
{
EventLog.LogEvent("GetProductWebDetails", "There was an error retrieving the product details. " + ex.Message, DotNetNuke.Services.Log.EventLog.EventLogController.EventLogType.ADMIN_ALERT);
}
return result;
}
企业资源计划代码
''' <summary>
''' Gets a Random Collection of <see cref="WebProductDetails"/> and pricing for the website.
''' </summary>
''' <param name="WebPortalId"><see cref="Integer"/>: Target Web Portal Id.</param>
''' <param name="CustomerCode"><see cref="String"/>: Customer Code.</param>
''' <param name="ShowRRPOnly"><see cref="Boolean"/>: Show RRP Only.</param>
''' <param name="ProductCount"><see cref="Integer"/>: Count of Products to Return.</param>
''' <param name="WebUserId"><see cref="Integer"/>: Web User Id.</param>
''' <returns><see cref="List(Of WebProductDetails)"/></returns>
''' <remarks>KeS/ZR 25/01/2021: created.</remarks>
Friend Function GetRandomProductWebDetails(WebPortalId As Integer, CustomerCode As String, ShowRRPOnly As Boolean, ProductCount As Integer, WebUserId As Integer) As List(Of WebProductDetails)
Dim Result As List(Of WebProductDetails) = GetRandomProductDetailsForWeb(WebPortalId, CustomerCode, ShowRRPOnly, ProductCount, WebUserId)
Return Result
End Function
''' <summary>
''' Gets a Random Collection of <see cref="WebProductDetails"/> and pricing for the website.
''' </summary>
''' <param name="WebPortalId"><see cref="Integer"/>: Target Web Portal Id.</param>
''' <param name="CustomerCode"><see cref="String"/>: Customer Code.</param>
''' <param name="ShowRRPOnly"><see cref="Boolean"/>: Show RRP Only.</param>
''' <param name="ProductCount"><see cref="Integer"/>: Count of Products to Return.</param>
''' <param name="WebUserId"><see cref="Integer"/>: Web User Id.</param>
''' <returns><see cref="List(Of WebProductDetails)"/></returns>
''' <remarks>KeS/ZR 25/01/2021: created.</remarks>
Friend Function GetRandomProductDetailsForWeb(WebPortalId As Integer, CustomerCode As String, ShowRRPOnly As Boolean, ProductCount As Integer, WebUserId As Integer) As List(Of WebProductDetails)
Dim result As List(Of WebProductDetails) = New List(Of WebProductDetails)
Try
result = dao.FinishedGoods.GetRandomWebProductDetailsByCount(ProductCount)
If result.IsNullOrEmpty() Then Return New List(Of WebProductDetails)
'User Id < 0 is not logged in, recommended price will always be fetched
Dim canWebUserViewCustomerPrice As Boolean = If(WebUserId <= 0, True, CheckIfUserHasWebRight(UserRights.WebUserCanViewStockItemPrices, WebUserId))
'override the User Right if DNN site set to always show recommended price no matter what
If (ShowRRPOnly) Then canWebUserViewCustomerPrice = False
For Each product In result
'Get the customer pricing, DS 21/06/2017 - fixed to get correct Web channel default ID, now uses default obj for this
Dim priceCalc As StockItemPricingForCustomer = blHelper.Fingoods.GetStockItemPricingForCustomer(DefaultStockItemPricingForWebArgs(product.StockCode, CustomerCode, Not canWebUserViewCustomerPrice, dao.Customers.SelectCustomerDealerType(CustomerCode)))
'RB 2017-07-11: Get the Kit Items for the product
Dim CodeList As IList(Of String)
CodeList = New List(Of String)
CodeList.Add(product.StockCode)
Dim relatedProducts As List(Of RelatedProduct) = dao.DaoPortal.SelectKitItems(CodeList)
product.KitItems = relatedProducts
product.ShowStockAvailable = blHelper.SystemRules.WebShowStockAvailability()
product.NoStockAvailableMessage = blHelper.SystemRules.WebNoStockAvailableMessage()
product.RetailPriceExVat = priceCalc.RetailPrice
product.CustomerDiscount = priceCalc.CustomerDiscount
product.CustomerPriceExVat = priceCalc.CustomerPrice
product.CustomerPriceInclVat = priceCalc.PriceWithTax
product.ExtraInfo = dao.FinishedGoods.SelectDetailedDescriptionForStockCode(product.StockCode).DescriptionHTML
product.DownloadLinksHTML = blHelper.Fingoods.GenerateProductDownloadLinksHTML(String.Empty, product.StockCode, "line-height:20px;text-align:left;", GetCompanyIdFromDatabaseName(dao.dbName, WebPortalId))
product.ProductImages = blHelper.Fingoods.GetProdcutImageLinksOnly(String.Empty, product.StockCode, GetCompanyIdFromDatabaseName(dao.dbName, WebPortalId))
' RB 2017-10-11: Lifestyle data for the product StockParent_MetaData
Dim MetaData As StockParent_MetaData = dao.ProductVariations.SelectMetaData(product.StockID)
product.ShowWebInfoButton = MetaData.ShowAdditionalWebInfo
product.WebInfoURL = MetaData.AdditionalWebInfoURL
product.WebInfoTarget = MetaData.AdditionalWebInfoTargetDisplay
product.WebInfoButtonText = MetaData.AdditionalWebInfoButtonText
' Rest of MetaData can also be returned here
'DS 21/01/2019 - Fetch Individual Warehouse Stock Levels and set the new property (following the business rule for showing stock)
If product.ShowStockAvailable Then product.WarehouseStockLevels = LLDataUtils.ConvertDataTableToObjectListUsingIMapFromDataTableInterface(Of PortalWarehouseStockLevel)(dao.DaoPortal.SelectWarehouseStockLevelsForPortal(New String() {product.StockCode}, Nothing))
product.ItemsInStock = If(product.ShowStockAvailable, product.WarehouseStockLevels.Sum(Function(w) w.Amount), -1)
Next
Catch ex As Exception
CommonServer.ErrorHandler.ServerError(ex, "An error occurred attempting to retrieve a Random Assortment of Products for the Website", ExceptionTypes.UndefinedException, True)
End Try
Return result
End Function
''' <summary>
''' Get Random product details for the web for the provided count of items.
''' </summary>
''' <returns>WebProductDetails</returns>
''' <remarks>KeS/ZR 25/01/2021: created.</remarks>
Friend Function GetRandomWebProductDetailsByCount(Count As Integer) As List(Of WebProductDetails)
Dim sql As New StringBuilder
With sql
.AppendLine($" SELECT TOP {Count} SP.Id 'StockID', SP.StockCode 'StockCode', ISNULL(SP.FriendlyTitle, FG.Description) 'Title', '' as 'Description', FG.DetailedDescription 'ExtraInfo', ")
.AppendLine(" SP.SlugURL 'SlugURL', ISNULL(SP.MetaTitle, ISNULL(SP.FriendlyTitle, FG.Description)) 'MetaTitle', SP.MetaDescription 'MetaDesc', SP.MetaKeywords 'MetaKeywords', SP.MainProductImageTitle 'MainImageTitle', sp.MainProductImageDescription 'MainImageDesc', fg.BarCode, fg.PrimaryPublishingCategories_ID AS PrimaryPublishingCategoryID,")
.AppendLine(" FG.Price 'RetailPriceExVat', COUNT(ISNULL(W.QUANTITY, 0)) 'ItemsInStock', PC.Name AS PrimaryPublishingCategoryName ")
.AppendLine(" FROM StockParent SP ")
.AppendLine(" INNER JOIN Fingoods FG ON FG.Id = SP.Id AND FG.IsDeleted = 0 AND FG.Publish = 1")
.AppendLine(" LEFT JOIN WAREHOUSESTOCK W ON w.FinGoods_ID = SP.Id ")
.AppendLine(" LEFT JOIN PublishingCategories AS PC ON PC.ID = FG.PrimaryPublishingCategories_ID AND PC.IsDeleted = 0 ")
.AppendLine(" WHERE SP.IsDeleted = 0 ")
.AppendLine(" GROUP BY SP.Id, SP.StockCode, ISNULL(SP.FriendlyTitle, FG.Description), FG.DetailedDescription, SP.SlugURL, ISNULL(SP.MetaTitle, ISNULL(SP.FriendlyTitle, FG.Description)), SP.MetaDescription, SP.MetaKeywords, SP.MainProductImageTitle, sp.MainProductImageDescription, FG.Price, fg.BarCode, fg.PrimaryPublishingCategories_ID, PC.Name")
.AppendLine(" ORDER BY NEWID() ")
End With
Using cmd As SqlCommandHelper = GetCommand(sql.ToString)
Return cmd.ExecuteList(Of WebProductDetails)
End Using
End Function