Scroll top on multiple elements - javascript

I have an accordion from Bootstrap 4 where I want when I click any of the accordion's tabs the page scrolls to its section.
$('.toggling-tabs').on('click', function () {
if ($('.sections').hasClass('collapsing')) {
$('html, body').animate({
scrollTop: $('.sections').offset().top
},
'slow');
}
});
I got this jQuery snippet where it works with only one of the tabs of the accordion. .toggling-tabs is the class for the accordion tabs and .sections is the class for the sections where when pressing any tab the page should scroll to.
How can I make the code work for all the tabs when any is clicked either using JS or jQuery.
Update:
<div class="col-lg-3 col-md-6 col-sm-12 toggling-tabs">
<div class="port-item p-4 bg-primary" data-toggle="collapse" data-target="#home">
<i class="fa fa-home d-block pb-2"></i> Home
</div>
</div>
<!-- Some stuff in between -->
<section class="collapse show sections" id="home">
<div class="card card-body bg-primary text-white py-5 banner">
<h2>Welcome to my portfolio</h2>
</div>
</section>
<section class="collapse collapsing sections" id="resume">
<div class="card card-body bg-success text-white py-5">
<h2>My Resume</h2>
</div>
</section>

Assuming you use the data-target attribute on the .toggling-tabs items, you can obtain the target in the event handler via $(this).data('target'). Than you can scroll to the element by id.
Now, to make the toggling working as expected, do it via javascript and remove the data-toggle attributes from the tags. Below is a working example.
$('.toggling-tabs [data-target]').on('click', function(event) {
var target = $(this).data('target');
$('.collapse:not(' + target + ')').collapse('hide');
$(target).collapse('show');
$('html, body').animate({
scrollTop: $(target).offset().top
}, 'slow');
});
#placeholder {
height: 150vh;
background-color: light-grey;
}
<div class="container">
<div class="row">
<div class="col-lg-3 col-md-6 col-sm-12 toggling-tabs">
<div class="port-item p-4 bg-primary" data-target="#home">
<i class="fa fa-home d-block pb-2"></i> Home
</div>
</div>
<div class="col-lg-3 col-md-6 col-sm-12 toggling-tabs">
<div class="port-item p-4 bg-success" data-target="#resume">
<i class="fa fa-home d-block pb-2"></i> Resume
</div>
</div>
</div>
</div>
<div id="placeholder">
</div>
<section class="collapse sections" id="home">
<div class="card card-body bg-primary text-white py-5 banner">
<h2>Welcome to my portfolio</h2>
</div>
</section>
<section class="collapse sections" id="resume">
<div class="card card-body bg-success text-white py-5">
<h2>My Resume</h2>
</div>
</section>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.3/js/bootstrap.min.js"></script>

$('.toggling-tabs').on('click', function () {
$('html, body').animate({
scrollTop: $('.sections').offset().top
},
'slow');
});
in your code it checks whether it has class collapsing i removed that so now it will work for all class section

Related

Cards with read-more in bootstrap

I am using the following code to achieve a three-column design with a read more button. I changed the columns to display:flex to make them the same height. It looks fine when in default state. When you open a read-more option though, the other buttons shift too. Is there a possibility to prevent the buttons from shifting?
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<!-- make cards same height -->
<section id="cards" class="py-5 bg-white">
<div class="container">
<div class="row">
<!-- diplay cards as flexbox, direction column and space between -->
<div class="col-12 col-sm-4 d-flex flex-column justify-content-between">
<!-- wrap text in a div -->
<div>
<h1>Shootings</h1>
<p>Willkommen bei den ganzen tollen Elementen</p>
<div class="collapse mb-3" id="collapseWidthExample1">
This is some placeholder content for a horizontal collapse. It's hidden by default and shown when triggered.
</div>
</div>
<!-- wrap button in a div -->
<div>
<button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWidthExample1" aria-expanded="false" aria-controls="collapseWidthExample">Read more</button>
</div>
</div>
<div class="col-12 col-sm-4 d-flex flex-column justify-content-between">
<div>
<h1>Shootings</h1>
<p>Willkommen bei den ganzen tollen Elementen. Willkommen bei den ganzen tollen Elementen.</p>
<div class="collapse mb-3" id="collapseWidthExample2">
This is some placeholder content for a horizontal collapse. It's hidden by default and shown when triggered.
</div>
</div>
<div>
<button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWidthExample2" aria-expanded="false" aria-controls="collapseWidthExample">Read more</button>
</div>
</div>
<div class="col-12 col-sm-4 d-flex flex-column justify-content-between">
<div>
<h1>Shootings</h1>
<p>Willkommen bei den ganzen tollen Elementen
<div class="collapse mb-3" id="collapseWidthExample3">
This is some placeholder content for a horizontal collapse. It's hidden by default and shown when triggered.
</div>
</p>
</div>
<div>
<button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWidthExample3" aria-expanded="false" aria-controls="collapseWidthExample">Read more</button>
</div>
</div>
</div>
</div>
</section>
Remove justify-content-between It might work
You can add the align-items-start class to your row div.
<div class="row align-items-start">
But that way you the cards will not have equal heights anymore.

Adjust <div>-height to window-height on Bootstrap website

Assume I have a simple website made with Bootstrap 4 containing header, navbar, content-area and footer.
My demo-website can be found and live-edited on JSFiddle: https://jsfiddle.net/26zda5xv/2/
Please find below a screenshot of the website too:
I want the <div class="container"> to fill out the whole page/window-height at least. (min-height?)
This should be done by extending the height of the <div id="content">.
Of course the solution should take care of various screen-resolutions/devices automatically.
How to do this correctly based on the JSFiddle?
Is there a build-in solution in Bootstrap 4 for this task?
Thank you!
to solve this we need 2 steps:
add d-flex flex-column min-vh-100 classes to the container.
add flex-grow-1 class to the content div
see this fiddle
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" />
<body class="bg-secondary">
<div class="container bg-white shadow border border-dark d-flex flex-column min-vh-100">
<img src="http://www.apexcartage.com/wp-content/uploads/2014/05/placeholder-blue.png" class="img-fluid" alt="Responsive image">
<nav class="navbar navbar-dark bg-dark">
<a class="navbar-brand" href="#">Navbar</a>
</nav>
<div id="content" class="my-3 flex-grow-1">
<p class="h3">Content</p>
</div>
<footer>
<div class="bg-dark text-white mt-4 p-3 border-info" style="border-top: 4px solid">
<h5 class="title">Footer</h5>
</div>
<div class="bg-info p-1"></div>
</footer>
</div>
</body>

JS matchMedia: Can you match the screen as well with this?

I have a two column layout where my footer copyright is on the left side. When I decrease the screen size to mobile for testing, the footer on the left, is put to the middle and the second column starts after the footer.
I can fix this with JavaScript with matchMedia(). However, matchMedia() only works on mobile. Is there a way to match media and screen? Something like matchMediaScreen()? See example:
.branding-color {
background-color: darkblue;
}
.welcome,
.students {
color: white;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container-fluid">
<div class="row vh-100">
<div class="col-md-4">
<section class="row logo-area mb-5 p-3">
<div class="col-6">
<a href="/index.php">
<img class="img-fluid" :src="logo" alt="Secret Logo" />
</a>
</div>
<div class="col-6 text-right">
<img class="img-fluid " :src="hpoLogo" alt="Secret Logo">
</div>
</section>
<!-- row logo-area -->
<div class="col-sm-12 d-flex justify-content-center flex-column text-center uni-center">
<div class="mb-5">
<img class="img-fluid uni-logo" :src="universityLogo" alt="" />
</div>
<div class="login mb-5">
<a class="btn btn-blue mr-2" href="/login.php">Login</a>
<a class="btn btn-green" href="/register.php">Register</a>
</div>
<nav class="nav flex-column mb-5">
Support
Privacy Policy
Terms & Conditions
</nav>
<div class="social">
<img :src="facebook" alt="" />
<img :src="twitter" alt="" />
<img :src="instagram" alt="" />
<img :src="mail" alt="" />
</div>
</div>
<footer>
<p class="text-center">© 2019 All rights reserved. Designed and hosted by Someone Special</p>
</footer>
</div>
<!-- col-md-3 -->
<div class="col-md-8 d-flex align-items-center justify-content-center branding-color">
<div class="col-md-8 welcome-white rounded">
<h2 class="welcome m-0 font-weight-bold">Welcome</h2>
<h2 class="students mb-5">Students</h2>
</div>
</div>
<!-- col-md-8 -->
<div class="m-footer"></div>
</div>
<!-- row -->
</div>
<!-- container-fluid -->
MDN says:
In JavaScript, you can use the Window.matchMedia() method to test the window against a media query.
So, for example:
const query = window.matchMedia("screen and (min-width: 992px)");
What you insert is just a string, so you can do some smart things pretty easily with template literals if you are using ES2015:
const min = 576;
const getMediaQuery = minWidth =>
window.matchMedia(`screen and (min-width: ${minWidth}px)`);
const query = getMediaQuery(min);
const screenTest = e =>
e.matches
? console.info(`The window is at least ${min}px wide.`)
: console.info(`The window is less than ${min}px wide.`);
query.addListener(screenTest);
screenTest(query);

How to select data from DIV's with something like $this?

given the following code snippet:
<div class="container-fluid" id="networdapp">
<div class="row" >
<div v-for="result in results" class="col-sm-6" >
<div class="card m-3 h-240 bg-light">
<div class="card-header text-center"> {{ result.title }} </div>
<div class="card-body" style="height:200px" >
<p class="card-text" v-html="result.prevDesc"></p>
</div>
<div class="card-footer bg-transparent border-info">
Details
</div>
</div>
</div>
</div>
</div>
How can I read data from a random div/unknown position in for div? I can't use PHP.
This <div ... id="networdapp"> is created depending on the results from a database. How can I get the data {{result.title}} from a random div when I click the "Details" button from it?
I tried to get it using JQuery but I ended up by selecting all data from all DIVs. Then I was thinking if I can do that with $this and I tried but still can't do it.
EDIT: There is the generated html code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Website Test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">WebSite for testing</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarWw1" aria-controls="navbarWw1" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarWw1">
<ul class="navbar-nav mr-auto mt-2 mt-lg-0">
<li class="nav-item active">
<a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="map">Map</a>
</li>
<li class="nav-item">
<a class="nav-link" href="about">About</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" id="myInput" type="search" onkeyup="myFunction()" placeholder="Find your next memories!">
</form>
</div>
</nav>
<div class="container-fluid" id="networdapp" style="display:none;">
<div class="row" >
<div v-for="result in results" class="col-sm-6" >
<div class="card m-3 h-240 bg-light" >
<div class="card-header text-center" > {{ result.title }} </div>
<div class="card-body" style="height:200px" >
<p class="card-text" v-html="result.prevDesc"></p>
</div>
<div class="card-footer bg-transparent border-info">
<a href="/details" class="btn btn-info" >Details</a>
</div>
</div>
</div>
</div>
</div>
</body>
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
function myFunction() {
var input , filter , OK = false ;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
if(filter.length > 0 ) {
document.getElementById("networdapp").style.display = "";
$( ".col-sm-6" ).each(function( index ) {
if ($(this).text().toUpperCase().indexOf(filter) > -1){
this.style.display="";
}else{
this.style.display="none";
//document.getElementById("networdapp").style.display = "none";
}
});
}
else{
document.getElementById("networdapp").style.display = "none";
}
}
</script>
<script type="text/javascript">
const vm = new Vue({
el: '#networdapp',
data: {
results:[]
},
mounted() {
axios.get('/getJson')
.then(response => {
this.results = response.data;
})
.catch( e => {
console.log(e);
});
}
});
</script>
</html>
The div has the class card-header, so...
$('.card-header').text()
//or
document.getElementsByClassName('card-header')[0].innerText
//or
document.querySelector('.card-header').innerText
//or
document.querySelectorAll('.card-header')[0].innerText
However, you want to get the one related to the button clicked. So that could look something like...
//create a delegate event handler on the container for all the buttons
$('#networdapp').on('click', '.btn.btn-info', function (e) {
//prevent the link so the runnable snippet stops jumping back to the top
e.preventDefault();
//find the parent div with the card class that is the parent to both
//the link and the title
var $card = $(this).closest('.card');
//find the nested card header in the card clicked
var $cardHeader = $card.find('.card-header');
//console log the text
console.log($cardHeader.text());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container-fluid" id="networdapp">
<div class="row">
<div v-for="result in results" class="col-sm-6" >
<div class="card m-3 h-240 bg-light">
<div class="card-header text-center"> title 1 </div>
<div class="card-body" style="height:200px" >
<p class="card-text" v-html="result.prevDesc"></p>
</div>
<div class="card-footer bg-transparent border-info">
Details
</div>
</div>
</div>
</div>
<div class="row">
<div v-for="result in results" class="col-sm-6" >
<div class="card m-3 h-240 bg-light">
<div class="card-header text-center"> title 2 </div>
<div class="card-body" style="height:200px" >
<p class="card-text" v-html="result.prevDesc"></p>
</div>
<div class="card-footer bg-transparent border-info">
Details
</div>
</div>
</div>
</div>
<div class="row">
<div v-for="result in results" class="col-sm-6" >
<div class="card m-3 h-240 bg-light">
<div class="card-header text-center"> title 3 </div>
<div class="card-body" style="height:200px" >
<p class="card-text" v-html="result.prevDesc"></p>
</div>
<div class="card-footer bg-transparent border-info">
Details
</div>
</div>
</div>
</div>
</div>
Using jQuery:
$("#networdapp .card-header.text-center").html()
So:
$(".btn.btn-info").click(function(){
console.log( $("#networdapp .card-header.text-center").html() );
})
Or:
$(".btn.btn-info").click(function(){
console.log( $(this).closest("#networdapp").find(".card-header.text-center").html() );
})
You can select div then use the context to select the button r other elements within.
$(".card").each(function(){
var that = this; // <--- the current div
var header = $(that).find(".card-header");
var detailBtn = $(that).find(".btn-info");
// set event handlers here
// Example:
detailBtn.click(function(){
alert(header.text());
});
});
Here is a working Example
Using jquery
$(this).parents("#networdapp").find(".card-header.text-center").text();
To remove unneccesay spaces you can use trim
$.trim($(this).parents("#networdapp").find(".card-header.text-center").text());

Only fire a function once on scroll

So, I'd like to fire a function only once on scroll.
The problem is that I don't get to fire the function only once. I've tried different solutions ( .on(), setting a counter, setting it outside/inside the window.scrollstop function) but nothing worked.
It does work... but it works whenever I scroll! :(
I don't think it's difficult, but.. I didn't get to make it work so far.
here's my code:
$(window).scroll(function(){
$('.sr-icons').toggleClass('scrolled', $(this).scrollTop() > 950);
});
CSS:
.sr-icons.scrolled {
opacity: 0.2;
}
and HTML:
<div class="container">
<div class="row">
<div class="col-lg-3 col-md-6 text-center">
<div class="mt-5 mx-auto">
<i class="fa fa-4x fa-superpowers text-primary mb-3 sr-icons"></i>
<h3 class="mb-3 text-dark">Sturdy Templates</h3>
<p class="text-muted mb-0">Our templates are updated regularly so they don't break.</p>
</div>
</div>
<div class="col-lg-3 col-md-6 text-center">
<div class="mt-5 mx-auto">
<i class="fa fa-4x fa-paper-plane text-primary mb-3 sr-icons"></i>
<h3 class="mb-3 text-dark">Ready to Ship</h3>
<p class="text-muted mb-0">You can use this theme as is, or you can make changes!</p>
</div>
</div>
<div class="col-lg-3 col-md-6 text-center">
<div class="mt-5 mx-auto">
<i class="fa fa-4x fa-newspaper-o text-primary mb-3 sr-icons"></i>
<h3 class="mb-3 text-dark">Up to Date</h3>
<p class="text-muted mb-0">We update dependencies to keep things fresh.</p>
</div>
</div>
<div class="col-lg-3 col-md-6 text-center">
<div class="mt-5 mx-auto">
<i class="fa fa-4x fa-cog fa-spin text-primary mb-3 sr-icons"></i>
<h3 class="mb-3 text-dark">I Work For You</h3>
<p class="text-muted mb-0">Just think about any website you want to have, I will make that a reality.</p>
</div>
</div>
</div>
</div>
If I understood you, you can do something like :
$(window).on('scroll', function(){
if($(this).scrollTop() > 950) {
$('.sr-icons').toggleClass('scrolled', true);
$(window).off('scroll');
}
});
As said in other comments, you should check wether you want $(this).scrollTop() > 950 or $(this).scrollTop() < 950
Edit : A more proper solution would be to remove only that specific handler, so you can attach other events on scroll if you ever want to :
var handler = function(){
if($(this).scrollTop() > 950) {
$('.sr-icons').toggleClass('scrolled', true);
$(window).off('scroll', handler);
}
}
$(window).on('scroll', handler);
You can use a flag variable, initially 0, then increment on scroll.
Then you can add check as
var flag=0;
$(window).scroll(function(){
if(flag==0){
$('.sr-icons').toggleClass('scrolled', $(this).scrollTop() > 950);
flag++;
}
});

Categories

Resources