Frustrations going back to jQuery – Dev Diaries #2

I’m having one of those days where I’m finding it impossible to get off the boring admin tasks such as email and end of month stuff (yes I’m aware it’s the fifth), every time I think I’m getting to the end another task pops up, anyway here’s the second instalment of dev diaries.

Email, timesheets and other admin done, let’s get on!

I’ve been asked to build a page that contains a slider where every slide contains an inner slider (slideception). The inner slider shows a main image and thumbnails to select another image and bring it into view. The thumbnails should overlap a little to do this I’ve used a combination of relative positioning and javascript to modify the left value of each thumbnail e.g

  • image a – left 0px
  • image b – left 10px
  • image c – left 20px

But this has brought about a problem, when there are too many images to fit on one row the images drops down (display: inline-block) with the exception that the image holds the left multiplier meaning it is too far left. So I need to reset the left value when we move to a new row. To do this I’m choosing to find out the size of the parent column and calculate how many items can fit on one row. I’m torn between using the current class of the parent column col-md-10 or finding a class that contains just col because the width of the container may change in future. I think the latter is a better option.

Helper functions

So far I’ve used helper functions one to search for the nearest parent element that contains a given class and a helper to return an array of parent elements.

function parents(elm) {

    let a = elm;

    const parents = [];

    while (a) {

        parents.push(a);

        a = a.parentNode;

    }

    return parents;

}

 

/**

* Given an element (child) search all parents classes to see

* if it has a class that contains a given string

*

* Note: If you are searching for 'col' and a parent has 'col-md-10'

* the function will return true

*

* @param child Element The child where the search will start from

* @param search String The class to search for

*/

function findNearestParent(child, search) {

    // Get all the parent elements and perform a search

    return parents(child).find(elm => {

        if(elm.classList) {

            for(let item of elm.classList) {

                // If a class exists with the given search return this element

                if ( item.indexOf(search) !== -1) {

                    return true;

                }

            }

        }

        // Nothing found

        return false;

    });

}

Now I just need to get the width of the parent and work out how many of the children I can fit in that space. Note: The reason why I’m not just using element.parentNode is that the images are in an unordered list which has a width of “auto”.

I’m having problems getting the width of the found parent when using:

parseInt(window.getComputedStyle(parent, null).width)

I’m getting a result of 100 even though I know it’s not. When I select the element in chromes dev tools and use the same code as above but with the $0 shortcut I’m getting 920 hmm…

parent.getBoundingClientRect().width

returns 0

I’m fairly confident that the problem is being caused by bxSlider (feel free to correct me) I’m able to get the widths of other elements with no problem. I’d like to remove bxSlider in favour of a vanilla js option but as this is a progression of an existing site I’m not sure it’s feasible with time constraints.

I decided to use the onSliderLoad callback of bxSlider to set the width of the information I needed in a global variable, I’m not happy with this but for the moment it’ll have to do.

So let’s just take a second to think about what it is that I need to do:

  • Work out how many items can be on each row
    • Divide the container width by item width
  • Loop through our items setting the left value by -10 each time
  • Use the index + 1 and compare it our max num of its if modulus 0
  • We’re about to start a new row and should set the left value back to zero

I Completed the above and it works as it should on load however I was still having problems getting the correct width on resize so I decided in the end that if the user resized the window or if the window was less than a certain width I would just remove the effect. Updating the value in the onSliderResize callback just didn’t give me the results I was looking for an, unfortunately, I don’t have the time remaining to spend on this currently, hopefully, we’ll get some more time to improve this later.

This was the second dev diary and I’ve got to say so far I’m feeling more stupid than empowered but I’m going to stick with it. Something I’m really liking is that it’s helping me to slow myself down and think through what I’m doing more.

Return to Mr Mad Hat homepage