1

I am new to JavaScript and have almost no idea of how functional programming works. I am running into a problem.

const cards = document.querySelectorAll('.card')
const descriptionCards = document.querySelectorAll('.description-card')

async function displayParagraph(descriptionId) {
    function timer(time) {
        return new Promise(resolve => setTimeout(resolve, time))
    }

    await timer(500)
    document.querySelector(descriptionId).style.display = 'block'
}

cards.forEach(card => {
    const cardIndex = card.id['card-'.length]

    card.addEventListener('mouseover', () => {
        document.querySelector('#description-card-' + cardIndex).style.height = '302px'
        displayParagraph('#description-' + cardIndex)
    })
    card.addEventListener('mouseout', () => {
        document.querySelector('#description-card-' + cardIndex).style.height = '0px'
        document.querySelector('#description-' + cardIndex).style.display = 'none'
    })
})

descriptionCards.forEach(descriptionCard => {
    const cardIndex = descriptionCard.id['description-card-'.length]

    descriptionCard.addEventListener('mouseover', () => {
        document.querySelector('#description-card-' + cardIndex).style.height = '302px'
        document.querySelector('#description-' + cardIndex).style.display = 'block'
    })
    descriptionCard.addEventListener('mouseout', () => {
        document.querySelector('#description-card-' + cardIndex).style.height = '0px'
        document.querySelector('#description-' + cardIndex).style.display = 'none'
    })
})
.absolute {
    position: absolute;
}

.first-row {
    left: 100px;
}

.first-column {
    top: 407px;
}

.card {
    background: #FFFFFF;
    width: 320px;
    height: 240px;
    border: 0;
    border-radius: 25px;
    box-shadow: 0px 1px 15px 10px #00000040;
    z-index: 1;
}

.card img {
    margin: auto;
}

/* Descriptions */
.description-card {
    position: absolute;
    top: 215px;
    width: 100%;
    height: 0px;
    background: #FFFFFF;
    border-radius: 0px 0px 25px 25px;
    transition: all 500ms;
}

.description {
    position: absolute;
    top: 45px;
    font-size: 16px;
    display: none;
}

#description-a {
    left: 28px;
    width: 263px;
}
<div class="first-row first-column absolute">
    <div id="card-a" class="card">
        <img src="organizations/panthera.png" alt="Panthera">
    </div>
    <div id="description-card-a" class="description-card">
        <p id="description-a" class="description">Panthera is the only organization in the world that is devoted exclusively to the conservation of the world’s 40 wild cat species and their ecosystems. Utilizing the expertise of the world’s premier cat biologists, Panthera develops and implements global strategies for the most imperiled large cats: tigers, lions, jaguars, snow leopards, cheetahs, pumas, and leopards.</p>
    </div>
</div>

This works perfectly. But the problem, as you can see, is that I am repeating the code for what happens when I am hovering over the card or the description-card. Basically, I want the same behaviour when I am hovering over either the card or the description-card. Naturally, this is a good place to use functions to avoid repeating code. So I tried doing this:

const cards = document.querySelectorAll('.card')
const descriptionCards = document.querySelectorAll('.description-card')

async function displayParagraph(descriptionId) {
    function timer(time) {
        return new Promise(resolve => setTimeout(resolve, time))
    }

    await timer(500)
    document.querySelector(descriptionId).style.display = 'block'
}

function hovering() {
    document.querySelector('#description-card-' + cardIndex).style.height = '302px'
    displayParagraph('#description-' + cardIndex)
}

function notHovering() {
    document.querySelector('#description-card-' + cardIndex).style.height = '0px'
    document.querySelector('#description-' + cardIndex).style.display = 'none'
}

cards.forEach(card => {
    const cardIndex = card.id['card-'.length]

    card.addEventListener('mouseover', hovering)
    card.addEventListener('mouseout', notHovering)
})

descriptionCards.forEach(descriptionCard => {
    const cardIndex = descriptionCard.id['description-card-'.length]

    descriptionCard.addEventListener('mouseover', hovering)
    descriptionCard.addEventListener('mouseout', notHovering)
})
.absolute {
    position: absolute;
}

.first-row {
    left: 100px;
}

.first-column {
    top: 407px;
}

.card {
    background: #FFFFFF;
    width: 320px;
    height: 240px;
    border: 0;
    border-radius: 25px;
    box-shadow: 0px 1px 15px 10px #00000040;
    z-index: 1;
}

.card img {
    margin: auto;
}

/* Descriptions */
.description-card {
    position: absolute;
    top: 215px;
    width: 100%;
    height: 0px;
    background: #FFFFFF;
    border-radius: 0px 0px 25px 25px;
    transition: all 500ms;
}

.description {
    position: absolute;
    top: 45px;
    font-size: 16px;
    display: none;
}

#description-a {
    left: 28px;
    width: 263px;
}
<div class="first-row first-column absolute">
    <div id="card-a" class="card">
        <img src="organizations/panthera.png" alt="Panthera">
    </div>
    <div id="description-card-a" class="description-card">
        <p id="description-a" class="description">Panthera is the only organization in the world that is devoted exclusively to the conservation of the world’s 40 wild cat species and their ecosystems. Utilizing the expertise of the world’s premier cat biologists, Panthera develops and implements global strategies for the most imperiled large cats: tigers, lions, jaguars, snow leopards, cheetahs, pumas, and leopards.</p>
    </div>
</div>

But this does not work as cardIndex is not defined in the hovering and notHovering functions. I can't figure out how to pass cardIndex into the hovering and notHovering functions since I am not supposed to call the functions but the pass in the function names as variables into the addEventListener functions.

3
  • 2
    You can try card.addEventListener('mouseover', ()=>hovering(cardIndex)) and make hovering accept cardIndex as parameter Commented Nov 17, 2020 at 17:48
  • @Ramesh I tried it and it worked. But I want to know, what is the benefit of using a higher-order function in addEventListener()? Why is the language designed this way? Commented Nov 17, 2020 at 18:08
  • This isn't really JS, but "most languages": scope your variables correctly. If you pull cardIndex out as a const inside your descriptionCards.forEach code, pass that as function argument, because const are block scoped: it doesn't exist outside that block, unless you forward it as argument. In the code you show, the hover function is trying to access something called cardIndex, but nothing with that name exist. Commented Nov 17, 2020 at 19:26

1 Answer 1

1

in response to the comment that you put and according to the title of question, I read an article about higher-order functions in js and this is the link of that:

https://jrsinclair.com/articles/2019/what-is-a-higher-order-function-and-why-should-anyone-care/

according to the definition :

A function that takes a function as an argument, or returns a function as a result

is a higher-order function. so the "addEventListener()" function is a higher-order function itself. so the benefit of using such a function is that you could pass different functions to them, for example you could pass a new "clicking" function like this:

card.addEventListener('click', ()=>clicking(cardIndex, cardNum, cardWidth))

as you could see this new "hypothetical function" could take three argument and have a complete different action, and this is the benefit of using higher-order functions in javascript.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.