0

I have a DNN module that will build a product Carousel using Lightslider.

When the page loads, it takes a couple of seconds to get 10 products from our ERP server database. While this is loading, when I try to navigate to another page, it won't redirect until the Ajax query has returned data. It will wait until the products have loaded, and then it will redirect to the link I clicked on about 5 seconds ago.

I have enabled async: true and tried to add async to the Server-side code, but no luck.

$(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();
        });
    });

On the server-side of the Controller I have attempted to use the following two ways to get data, but it seems like it makes no difference.

Controller Code without Async Code (Test 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;
            }
        }

Controller Code with Async Code (Test 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;
            }

        }

I have even attempted to do the Ajax call differently using "Then", but no luck.

$(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);
        });
}

UPDATE

I have changed the Front-End Code to use a normal XMLHttpRequest instead of JQuery Ajax. I have two videos below to show what it is exactly doing and the Javascript Ajax code below that.

Video 1 (Build Product Carousel)
https://www.youtube.com/watch?v=n637FGv3e9U

Video 2 (Log Product Titles only to Console Log)
https://www.youtube.com/watch?v=8mHNcgBoe-Q

Javascript Ajax Code:

$(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);
            })
        }
    };

Controller Code:

/// <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;
        }
    }

Common Class

/// <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;
        }

ERP Code

        ''' <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
Tig7r
  • 525
  • 1
  • 4
  • 21
  • if i dont do a mistake ,await = wait the end of processus. If you want async, put off – Frenchy Feb 05 '21 at 13:12
  • Ok, so I have removed Await and Async from both the JQuery Ajax function and the server-side code, it does the same. It waits and then redirects. – Tig7r Feb 05 '21 at 13:53
  • no you have to keep Async.. – Frenchy Feb 05 '21 at 13:57
  • I have removed Await only from both the Front and Back-end and also tested with the front-end only having async, then the server only having async without async on the front-end, but It still does the same thing for some reason. – Tig7r Feb 05 '21 at 15:00
  • let's return to basis of problem,what is the size of your picture? have you checked that? because if one image does 3mb, 30mb does a certain amount of time to download... – Frenchy Feb 05 '21 at 15:28
  • i suppose in a first time, you download just link? and after the html does the job to laod images? your images are on your server or anyways on the web? are you using a plugin carousel? – Frenchy Feb 05 '21 at 15:39
  • I have tested to see if it was images with the network tab in the Google Chrome tools, but the images are small, about 80kb. I have even changed the way the DOM builds and just made it to write the product titles to the console log. Even if the DOM does not need to render the images, it seems that DNN waits for the server data to come back before it can redirect. Our data is stored on our own ERP system and fetches the list of data with a SQL query from the ERP database. The controller calls a method that will call another method which then request the data from our ERP system with WCF. – Tig7r Feb 06 '21 at 16:24
  • We use one call to our WCF function on our ERP server to fetch all product data, like the link, title, pricing and the images REST links. – Tig7r Feb 06 '21 at 16:26

0 Answers0