Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Jquery slidetoggle code to Javascript

How can I convert the jQuery slidetoggle() function into Javascript?

 var $context = getContext(context);

        $($context).on('click', '.m_menu', function () {
            $('.w_nav').slideToggle();
        });
like image 465
K2R Avatar asked Apr 29 '15 16:04

K2R


3 Answers

Well this is not converting the jQuery code to javascript, but rather doing it in plain javascript. It can be achieved in different ways. Here are two that comes to my mind:

HTML:

<button id="mbtn" onclick="slideToggle()">SlideToggle</button>
<div id="mdiv">Some context</div>

1. Using javascript's setInterval :
Having a boolean value to keep track of whether we need to slideUp or slideDown (toggle) and using setInterval to increase/decrease the height.

jsfiddle DEMO

Javascript:

var slideOpen = true;
var heightChecked = false;
var initHeight = 0;
var intval = null;

function slideToggle() {
    window.clearInterval(intval);
    var mdiv = document.getElementById('mdiv');
    if(!heightChecked) {
        initHeight = mdiv.offsetHeight;
        heightChecked = true;
    }
    if(slideOpen) {
        var h = initHeight;
        slideOpen = false;
        intval = setInterval(function(){
            h--;
            mdiv.style.height = h + 'px';
            if(h <= 0)
                window.clearInterval(intval);
            }, 1
        );
    }
    else {
        var h = 0;
        slideOpen = true;
        intval = setInterval(function(){
            h++;
            mdiv.style.height = h + 'px';
            if(h >= initHeight)
                window.clearInterval(intval);
            }, 1
        );
    }
}

2. Using CSS3 transition:
Getting help from CSS3 transition to go along with javascript which will make it a lot easier to achieve the slide effect. Then we'll only need to change the height in javascript and the rest is done.

jsfiddle DEMO

CSS:

#mdiv {
    /* other styles */
    -webkit-transition: all 1s ease-in-out;
    transition: all 1s ease-in-out;
}

Javascript:

var slideOpen = true;
var heightChecked = false;
var initHeight = 0;

function slideToggle() {
    var mdiv = document.getElementById('mdiv');
    if(!heightChecked) {
        initHeight = mdiv.offsetHeight;
        heightChecked = true;
    }
    if(slideOpen) {
        slideOpen = false;
        mdiv.style.height = '0px';
    }
    else {
        slideOpen = true;
        mdiv.style.height = initHeight + 'px';
    }
}

EDIT:
If we want the starting height to be 0, then we'll need a few changes:

var slideOpen = false;
//var heightChecked = false;
var initHeight = 120; //height of the element when it's fully open

And we need to comment this bit out:

/*
if(!heightChecked) {
    initHeight = mdiv.offsetHeight;
    heightChecked = true;
}
*/

jsfiddle DEMO

EDIT #2
As Sandro pointed out, context wasn't actually getting hidden so updated the fiddles and added overflow-y: hidden; and changed the text color for visibility. Also changed open to slideOpen since open is sort of a reserved word.

like image 129
Samurai Avatar answered Nov 09 '22 10:11

Samurai


To reimplement (convert) jquery slideToggle() to vanilla javascript, you need to reimplement jquery slideUp() and slideDown() as well.

var DOMAnimations = {
    
    /**
    * SlideUp
    *
    * @param {HTMLElement} element
    * @param {Number} duration
    * @returns {Promise<boolean>}
    */
    slideUp: function (element, duration = 500) {

        return new Promise(function (resolve, reject) {

            element.style.height = element.offsetHeight + 'px';
            element.style.transitionProperty = `height, margin, padding`;
            element.style.transitionDuration = duration + 'ms';
            element.offsetHeight;
            element.style.overflow = 'hidden';
            element.style.height = 0;
            element.style.paddingTop = 0;
            element.style.paddingBottom = 0;
            element.style.marginTop = 0;
            element.style.marginBottom = 0;
            window.setTimeout(function () {
                element.style.display = 'none';
                element.style.removeProperty('height');
                element.style.removeProperty('padding-top');
                element.style.removeProperty('padding-bottom');
                element.style.removeProperty('margin-top');
                element.style.removeProperty('margin-bottom');
                element.style.removeProperty('overflow');
                element.style.removeProperty('transition-duration');
                element.style.removeProperty('transition-property');
                resolve(false);
            }, duration)
        })
    },

    /**
    * SlideDown
    *
    * @param {HTMLElement} element
    * @param {Number} duration
    * @returns {Promise<boolean>}
    */
    slideDown: function (element, duration = 500) {

        return new Promise(function (resolve, reject) {

            element.style.removeProperty('display');
            let display = window.getComputedStyle(element).display;

            if (display === 'none') 
                display = 'block';

            element.style.display = display;
            let height = element.offsetHeight;
            element.style.overflow = 'hidden';
            element.style.height = 0;
            element.style.paddingTop = 0;
            element.style.paddingBottom = 0;
            element.style.marginTop = 0;
            element.style.marginBottom = 0;
            element.offsetHeight;
            element.style.transitionProperty = `height, margin, padding`;
            element.style.transitionDuration = duration + 'ms';
            element.style.height = height + 'px';
            element.style.removeProperty('padding-top');
            element.style.removeProperty('padding-bottom');
            element.style.removeProperty('margin-top');
            element.style.removeProperty('margin-bottom');
            window.setTimeout(function () {
                element.style.removeProperty('height');
                element.style.removeProperty('overflow');
                element.style.removeProperty('transition-duration');
                element.style.removeProperty('transition-property');
            }, duration)
        })
    },

    /**
    * SlideToggle
    *
    * @param {HTMLElement} element
    * @param {Number} duration
    * @returns {Promise<boolean>}
    */
    slideToggle: function (element, duration = 500) {

        if (window.getComputedStyle(element).display === 'none') {

            return this.slideDown(element, duration);

        } else {

            return this.slideUp(element, duration);
        }
    }
}

// ------------------------------------------------------

document.addEventListener("DOMContentLoaded", function() {

    var button = document.getElementById('slideToggle');

    var cardElement = document.getElementById('firstCard');

    button.addEventListener('click', function(event) {

        event.preventDefault();

        DOMAnimations.slideToggle(cardElement);
    });

});
* {
    box-sizing: border-box;
}

/* Add a gray background color with some padding */
body {
    font-family: Arial;
    padding: 20px;
    background: #f1f1f1;
}

/* Header/Blog Title */
.header {
    padding: 10px;
    font-size: 24px;
    text-align: center;
    background: white;
}

/* Create two unequal columns that floats next to each other */
/* Left column */
.leftcolumn {   
    float: left;
    width: 100%;
}

/* Fake image */
.fakeimg {
    background-color: #aaa;
    width: 100%;
    padding: 20px;
}

/* Add a card effect for articles */
.card {
    position:relative;
    background-color: white;
    padding: 20px;
    margin-top: 20px;
}

#slideToggle {
    background-color: #f9f5f5;
    color: black;
    border: 2px solid #a9b5a9;
    padding: 5px;
    margin-top:20px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
    cursor: pointer;
    font-weight: bold;
    border-radius: 5px;
}

/* Clear floats after the columns */
.row:after {
    content: "";
    display: table;
    clear: both;
}

/* Footer */
.footer {
    padding: 20px;
    text-align: center;
    background: #ddd;
    margin-top: 20px;
}

/* Responsive layout - when the screen is less than 800px wide, make the two columns stack on top of each other instead of next to each other */
@media screen and (max-width: 800px) {
    .leftcolumn, .rightcolumn {   
        width: 100%;
        padding: 0;
    }
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>

<div class="header">
    <h2>Blog Name</h2>
</div>

<div class="row">
    <div class="leftcolumn">
        <button id="slideToggle">slideToggle</button>
        <div class="card" id="firstCard">
            <h2>FIRST TITLE HEADING</h2>
            <h5>Title description, Dec 7, 2018</h5>
            <div class="fakeimg" style="height:200px;">Image</div>
            <p>Some text..</p>
            <p>Sunt in culpa qui officia deserunt mollit anim id est laborum consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p>
        </div>
        <div class="card">
            <h2>SECOND TITLE HEADING</h2>
            <h5>Title description, Dec 7, 2018</h5>
            <div class="fakeimg" style="height:200px;">Image</div>
            <p>Some text..</p>
            <p>Sunt in culpa qui officia deserunt mollit anim id est laborum consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco.</p>
        </div>
    </div>
</div>

<div class="footer">
    <h2>Footer</h2>
</div>

</body>
</html>
like image 30
chebaby Avatar answered Nov 09 '22 10:11

chebaby


I am giving a lightweight answer. You can think of it as a skeleton example, and you can play with it, style it later, according to your preferences.

Before you begin, I would like to clarify that I'm not converting jQuery slideToggle() function into one in JavaScript

All I'm doing is, trying to replicate that function in the simplest possible form!

Step 1:

Create a button/(any other element), which you can link with an eventListener.

Step 2:

Create an element, which you want to toggle/slide/whatever you want to call it!

Step 3:

Go ahead with your javaScript, and create a conditional setInterval() for a function linked with that eventListener.

You can give your suggestions in the comment section.

var animxB = 0;
var anim2B = 0;
document.getElementById("animB").addEventListener("click", performB);

function performB() {
anim2B++;
anim3B = anim2B % 2;
var fram1B = setInterval(framB, 1);

function framB() {
    if (anim3B == 1) {
        animxB++;
        document.getElementById("divB").style.width = animxB + "px";
        document.getElementById("divB").style.height = animxB + "px";
        if (animxB >= 200) {
            clearInterval(fram1B);
            document.getElementById("animB").innerHTML = "Click(-)";
        }
    }
    if (anim3B == 0) {
        animxB--;
        document.getElementById("divB").style.width = animxB + "px";
        document.getElementById("divB").style.height = animxB + "px";
        if (animxB <= 0) {
            clearInterval(fram1B);
            document.getElementById("animB").innerHTML = "Click(+)";
        }
    }


}
}
<!DOCTYPE html>
<html>

<head></head>

<body>
<button id="animB" style="font-weight:bold; color:brown;">Click(+)</button>
<div id="divB" style="width:0; height:0; overflow:auto; color:gray; font-family:sans-serif; font-size:13px;">
    &lt;path d="M10 10 v80 h80 v-80 h-80" fill="gray" stroke="black" stroke-width="1" /&gt; &lt;path d="M40 10 v20" stroke="blue" stroke-width="0.5" /&gt; &lt;path d="M10 30 h30" stroke="red" stroke-width="0.5" /&gt; &lt;circle cx="40" cy="30" r="2" fill="purple" stroke="purple" stroke-width="1" /&gt;
</div>
</body>

</html>
like image 26
Alfha Avatar answered Nov 09 '22 11:11

Alfha