Return to Solutions Overview <-

Complex thing #001

Super cool, kinda not used javascript loader for real complicated dom element strucutre.

(Still under development as of March 15th 2023)

This code is just beautiful in terms of architecture, but we will probably discard it when we move to wized v2 and decide to work more No-Code. (For scalability reasons - the code itself works great).

(Correction: At the time of publication, there is still a chance that this beauty will be the backbone of a wonderful startup from Australia).

<script>
var Webflow = Webflow || []
Webflow.push(function () { // Run all the code after the site is fully loaded.  

/* Start of: BMG data code */

// Global strings
const pageCountSelector = '[bmg-data = "page count"]'
const mainDynItemSelector = '[bmg-data = "main dyn item"]'
const groupIdSelector = '[bmg-data = "group-id"]'
const swapCategorySelector = '[bmg-data = "swap category"]'
const productNameSelector = '[bmg-data = "product-name"]'
const wListWrapperSelector = '.w-dyn-list' 
const productDataGroupSelector = '[bmg-data-group]'

// Global calc values
const numberOfAvailableProducts = parseInt( $( pageCountSelector ).text().split('/')[1] ) || 179 // Backup value
$( pageCountSelector ).closest( wListWrapperSelector ).remove()


// Global main function
function main()
{
    $( mainDynItemSelector ).show() // # Delete this line later # 

    // s1_living_dining_lower
    $( productDataGroupSelector ).each(function()
    {
        // Local elements & variables
        let styleGroupId = $(this).attr( productDataGroupSelector.replace('[', '').replace(']', '') )
        fillDynStyleData( styleGroupId )
    })
}


// Helper functions
function fillDynStyleData( id )
{
    // Get products of style x
    let styleItemsArray = []
    
    $( mainDynItemSelector ).each(function()
    {
        let $dynItem = $(this)
        let $groupIds = $(this).find( groupIdSelector )

        $groupIds.each(function()
        {
            if ( $(this).text() == id )
            {
                styleItemsArray.push( $dynItem )
            }
        })
    })

    // Get swap options for these
    for ( let i = 0, n = styleItemsArray.length; i < n; i++  )
    {
        let $mainDynItem = styleItemsArray[i]
        $mainDynItem.find( swapCategorySelector ).each(function()
        {
            let $thisSwapCategory = $(this)
            let thisProductName = $(this).closest( mainDynItemSelector ).find( productNameSelector ).text()
            let swapCategoryText = $(this).text()
            console.log( '\nThis product: "' + thisProductName + '" has these swap options -->' )
            
            $( swapCategorySelector ).each(function(index)
            {
                if ( swapCategoryText == $(this).text() )
                {
                    let swapProductName = $(this).closest( mainDynItemSelector ).find( productNameSelector ).text()
                    if ( thisProductName !== swapProductName  )
                    {
                        console.log( index+1 + ' --- ' + swapProductName )
                    }
                }
            })
        })
    }
}

// Call main when all elements are loaded
const loopTimeoutAmount = 100 //ms
function checkProductLoad()
{
    let numberOfLoadedProducts = $( mainDynItemSelector ).length
    
    if ( numberOfLoadedProducts >= numberOfAvailableProducts )
    {
        console.log(`Finished loading: ${numberOfLoadedProducts} of ${numberOfAvailableProducts} products!`) 
        main()
    }
    else
    {
        setTimeout(() =>
        {
            console.log(`${numberOfLoadedProducts} of ${numberOfAvailableProducts} products loaded...`)
            checkProductLoad()
        }, loopTimeoutAmount)
    }
}
checkProductLoad()

/* End of: BMG data code */
  
}) // The end.
</script>

Here is v0.1.1 of the same script. Not gonna be used, but still wonderful in complexity -> (Lots of free work; but beautiful and it was a good mental exercise)

<script>
var Webflow = Webflow || []
Webflow.push(function () { // Run all the code after the site is fully loaded.  

/* Start of: BMG data code */

// Global strings
const dataStorageWrapperSelector = '.data-storage',
    pageCountSelector = '[bmg-data = "page count"]',
    mainDynItemSelector = '[bmg-data = "main dyn item"]',
    groupIdSelector = '[bmg-data = "group-id"]',
    swapCategorySelector = '[bmg-data = "swap category"]',
    wListWrapperSelector = '.w-dyn-list' ,
    productDataGroupSelector = '[bmg-data-group]',
    imageSelector = '.data-storage_image',
    nameSelector = '[bmg-data = "name"]',
    skuSelector = '[bmg-data = "sku"]',
    priceSelector = '[bmg-data = "price"]',
    descriptionSelector = '[bmg-data = "description"]',
    popUpWrapperSelector = '.pop-up_content-container',
    popUpItemSelector = '[bmg-data = "popUpItem"]',
    popUpLineSelector = '[bmg-data = "popUpLine"]',
    popUpItemImageSelector = '.app_pop-up_product-image',
    popUpSwapImageSelector = '.app_pop-up_product-option-image',
    popUpSwapGridSelector = '.app_pop-up_product-option-gird',
    popUpProductNameSelector = '.text-style-1line'

// Global calc values
const numberOfAvailableProducts = parseInt( $( pageCountSelector ).text().split('/')[1] ) || 179 // Backup value
$( pageCountSelector ).closest( wListWrapperSelector ).remove()


// Global main function
function main()
{
    // Loop through pick & adjust's
    $( productDataGroupSelector ).each(function()
    {
        // Local elements & variables
        let styleGroupId = $(this).attr( productDataGroupSelector.replace('[', '').replace(']', '') )
        let jsObject = createJsObject( styleGroupId )

        // Local functions
        changeThumbnail( jsObject, styleGroupId )
        updateSelectOptions( jsObject, styleGroupId )
    })
    // $( dataStorageWrapperSelector ).remove() // # Uncomment later #
}


// # Helper functions #

// Update select options
function updateSelectOptions( jsObject, id )
{
    let $popUp = $( productDataGroupSelector.replace(']', '') + '= "' + id + '"]' ).find( popUpWrapperSelector )
    let $item = $popUp.find( popUpItemSelector ).first()
    let $line = $popUp.find( popUpLineSelector ).first()

    $popUp.children().slice(2).remove()
    $popUp.children().last()

    for ( let i = 0, n = jsObject.length; i < n; i++  )
    {
        let itemClone = $item.clone()
        $popUp.children().last().after( itemClone )

        if ( i < n -1 )
        {
            let lineClone = $line.clone()
            $popUp.children().last().after( lineClone )
        }

        // Change items
        let $itemClone = $popUp.find( popUpItemSelector ).eq(i)
        let $itemImage = $itemClone.find( popUpItemImageSelector )
        let $itemName = $itemClone.find( popUpProductNameSelector )

        $itemName.text( jsObject[i].item.name )

        $itemImage
            .attr
            ({
                'src': jsObject[i].item.imageUrls[0],
                'srcset': '',
                'product-price': '$' + jsObject[i].item.price
            })
            .css
            ({
                'height': '250px',
                'object-fit': 'contain'
            })

        // Change swaps
        let $swapScript = $popUp.find( popUpSwapGridSelector ).eq(i)
        $swapScript.empty()
        
        for ( let i2 = 0, n2 = jsObject[i].swaps.length; i2 < n2; i2++  )
        {
            let productName = jsObject[i].swaps[i2].item.name
            let imageUrl = jsObject[i].swaps[i2].item.imageUrls[0]
            
            $swapScript.append(
                `<img src="${imageUrl}" alt="${productName}" class="${ popUpSwapImageSelector.slice(1) }" style="max-height: 155px; object-fit: contain;">`
            )
        }
    }
}

// Change style thumbnail
function changeThumbnail( jsObject, id )
{
    let $thumbnail = $( productDataGroupSelector.replace(']', '') + '= "' + id + '"]' ).find( 'img' ).first()
    
    for ( let i = 0, n = jsObject.length; i < n; i++  )
    {
        let productName = jsObject[i].item.name
        let imageUrl = jsObject[i].item.imageUrls[0]

        // Add elements dynamically
        $thumbnail.after(
            `<img src="${imageUrl}" alt="${productName}" style="width: 40%; max-height: 175px; margin: 5%; object-fit: contain;">`
        )
    }

    $thumbnail.remove()
}

// Create advanced JavaScript object
function createJsObject( id )
{
    // Get products of style x
    let jsObject = []
    
    $( mainDynItemSelector ).each(function()
    {
        let $dynItem = $(this)
        let $groupIds = $dynItem.find( groupIdSelector )

        $groupIds.each(function()
        {
            if ( $(this).text() == id )
            {
                let imageUrls = []
                $dynItem.find( imageSelector ).each(function()
                {
                    imageUrls.push( $(this).attr('src') )
                })
                    
                jsObject.push
                    ({ 
                        'item': 
                        {
                            'name': $dynItem.find( nameSelector ).text(),
                            'sku': $dynItem.find( skuSelector ).text(),
                            'price': $dynItem.find( priceSelector ).text(),
                            'description': $dynItem.find( descriptionSelector ).clone(),
                            'imageUrls': imageUrls,
                            '$': $dynItem
                        },
                        'swaps': []
                    })
            }
        })
    })

    // Get swap options for these
    for ( let i = 0, n = jsObject.length; i < n; i++  )
    {
        let $mainDynItem = jsObject[i].item.$
        $mainDynItem.find( swapCategorySelector ).each(function()
        {
            let $thisSwapCategory = $(this)
            let thisProductName = jsObject[i].item.name
            let swapCategoryText = $(this).text()
            
            $( swapCategorySelector ).each(function(index)
            {
                if ( swapCategoryText == $(this).text() )
                {
                    let $swapDynItem = $(this).closest( mainDynItemSelector )
                    let swapProductName = $swapDynItem.find( nameSelector ).text()
                    
                    if ( thisProductName !== swapProductName  )
                    {
                        let imageUrls = []
                        $swapDynItem.find( imageSelector ).each(function()
                        {
                            imageUrls.push( $(this).attr('src') )
                        })
                        
                        jsObject[i].swaps.push
                        ({
                            'item':
                            {
                                'name': swapProductName,
                                'sku': $swapDynItem.find( skuSelector ).text(),
                                'price': $swapDynItem.find( priceSelector ).text(),
                                'description': $swapDynItem.find( descriptionSelector ).clone(),
                                'imageUrls': imageUrls,
                                '$': $swapDynItem
                            }    
                        })
                    }
                }
            })
        })
    }

    return jsObject
}

// Call main when all elements are loaded
const loopTimeoutAmount = 100 //ms
function checkProductLoad()
{
    numberOfLoadedProducts = $( mainDynItemSelector ).length
    
    if ( numberOfLoadedProducts >= numberOfAvailableProducts )
    {
        console.log(`Finished loading: ${numberOfLoadedProducts} of ${numberOfAvailableProducts} products!`) 
        main()
    }
    else
    {
        setTimeout(() =>
        {
            console.log(`${numberOfLoadedProducts} of ${numberOfAvailableProducts} products loaded...`)
            checkProductLoad()
        }, loopTimeoutAmount)
    }
}
checkProductLoad()

/* End of: BMG data code */
  
}) // The end.
</script>

FAQs

You still have an open question about BMG.studio and how we operate. Chances are good that you will find what you are looking for here:

Why does this FAQ exist?

Well. As of Wednesday, March 15th 2023, I think this component looks really cool.

Can I clone this FAQ component?

Yes. Yes you can. You can do so -> here <-

Still have questions?

It's okay to reach out. Use either email or our calendar tool