I was wondering if there was a way to have a centered item shift smoothly when its width changes?
In my case, I have a piece of text on the left that stays the same, and the piece of text on the right will change depending on what page you are on.
<div id="title-container">
<h1 class="inline-header">example.</h1>
<h1 id="title-category" class="inline-header">start</h1>
</div>
The total width of this will change as a result, and it will shift abruptly.
Here is a jsfiddle demonstrating the problem.
https://jsfiddle.net/sm3j26aa/3/
I've currently worked around it by just fixing the left side using relative positioning and translates, but if I can get the smooth transition, I would rather do that.
Thanks for any help!
Instead of fading just the right portion in and out, you'll need to fade the entire line.
Also, there is no need for individual functions for each word change. Just have one function that accepts the new word as a parameter.
Lastly, don't use inline HTML event attributes to set up event handlers. It:
creates spaghetti code that is more difficult to read
creates anonymous wrapper functions that alter the this binding
within the function
doesn't follow W3C DOM Even Standards
Instead set up your event handlers in JavaScript.
var $titleContainer = $('#title-container');
var $titleCategory = $('#title-category');
$("button").click(function(){ change(this.textContent); })
function change(text) {
$titleContainer.fadeOut(300, function() {
$titleCategory.text(text);
$titleContainer.fadeIn(600);
})
}
#title-container, #button-container { text-align: center; }
.inline-header { display: inline-block; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="title-container">
<h1 class="inline-header left">example.</h1>
<h1 id="title-category" class="inline-header">start</h1>
</div>
<div id="button-container">
<button>Sample</button>
<button>Hello</button>
<button>SampleX2</button>
</div>
var $titleCategory = $('#title-category');
function changeToSample() {
$titleCategory.fadeOut(300, function() {
$titleCategory.text('sample');
$titleCategory.fadeIn(600);
document.getElementById('title-container').style.marginLeft = `calc(50% - 14em/2)`;
})
}
function changeToHello() {
$titleCategory.fadeOut(300, function() {
$titleCategory.text('hello');
$titleCategory.fadeIn(600);
document.getElementById('title-container').style.marginLeft = `calc(50% - 12em/2)`;
})
}
function changeToDoubleSample() {
$titleCategory.fadeOut(300, function() {
$titleCategory.text('samplesample');
$titleCategory.fadeIn(600);
document.getElementById('title-container').style.marginLeft = `calc(50% - 20em/2)`;
})
}
#title-container {
margin-left: calc(50% - 12em/2);
transition: .2s;
}
#button-container {
text-align: center;
}
.inline-header {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="title-container">
<h1 class="inline-header">example.</h1>
<h1 id="title-category" class="inline-header">start</h1>
</div>
<div id="button-container">
<button onclick="changeToSample();">Sample</button>
<button onclick="changeToHello();">Hello</button>
<button onclick="changeToDoubleSample();">SampleX2</button>
</div>
Related
I have the code below to change the height of a div to equal that of its parent.
$('#infodiv').css("height",$("#infocol").outerHeight());
The problem is that the height of the child element #infocol, is no longer dynamic if i load new content inside of it. Is there a way to make the child element dynamic again after i have set the height with the above code?
I have tried to reconfigure its height after the content is loaded with the same code, but so far that hasn't worked.
There is a way you can solve this issue using ResizeObserver
However, note that it's not supported in some browsers, check the page I've linked for further details.
Here is a working example:
$(function () {
$("#add-content").click(function () {
$(".first-col").append("<p>More dynamic content...</p>");
});
// keep the second-col same size as first
$(".second-col").css('height', $(".first-col").outerHeight());
const resizeObserver = new ResizeObserver(function (entries) {
for (let entry of entries) {
// once one of the entry changes we want to update the other size too!
$(".second-col").css('height', $(entry.target).outerHeight());
}
});
// We need to pass the actual DOM node, hence the [0]
resizeObserver.observe($(".first-col")[0]);
});
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.container {
width: 23.5rem;
margin: 1rem auto;
}
.first-col {
background: cornflowerblue;
}
.second-col {
background: crimson;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="first-col">
<p>Some content</p>
<p>Some content</p>
<button id="add-content">Add content</button>
</div>
<div class="second-col"></div>
</div>
Though, I suggest before implementing it like that, that you look into how flex works or simply even min-height might be the proper tool for the issue here. If you're out of options, feel free to use ResizeObserver, but it's considered an exotic solution!
I've created a template part in PHP that copies a button to each slide in a carousel using fullpage.js. The template part has a hidden div that should open up navigation for each slide. Trying the code below, I can only get this button to work on the first slide. I'm thinking an iterated class name might help, but not sure why querySelectorAll wouldn't do it. Any advice appreciated...
http://www.pulsecreative-clients.com/staging/hogshead/#golf
const clickOnMe = document.querySelectorAll(".course-button");
let clickOnMe = document.querySelectorAll(".course-button");
Array.from(clickOnMe).forEach(el => {
el.addEventListener("click", e => {
let showBox = e.currentTarget.nextElementSibling;
showBox.classList.toggle("open-nav");
});
});
.subnav-content {
position: fixed;
bottom: 15%;
z-index: 1;
box-sizing: border-box;
padding: 10px;
background-color: #000;
display: none;
}
.golfcoursebutton {
box-sizing: content-box;
min-width: 30px;
height: 30px;
padding: 4px;
margin: 4px;
background-color: #fff;
color: #000;
text-align: center;
}
.open-nav {
display: block;
}
<div id="jump-button" class="jumpbuttons-container">
<div class="subnav">
<button class="course-button">
JUMP TO <i class="fa fa-angle-up"></i>
</button>
<div class="subnav-content">
<div style="display: flex;">
<div class="golfcoursebutton">1</div>
<div class="golfcoursebutton">2</div>
<div class="golfcoursebutton">3</div>
<div class="golfcoursebutton">4</div>
<div class="golfcoursebutton">5</div>
<div class="golfcoursebutton">6</div>
</div>
<div style="display: flex;">
<div class="golfcoursebutton">7</div>
<div class="golfcoursebutton">8</div>
<div class="golfcoursebutton">9</div>
<div class="golfcoursebutton">10</div>
<div class="golfcoursebutton">11</div>
<div class="golfcoursebutton">12</div>
</div>
<div style="display: flex;">
<div class="golfcoursebutton">13</div>
<div class="golfcoursebutton">14</div>
<div class="golfcoursebutton">15</div>
<div class="golfcoursebutton">16</div>
<div class="golfcoursebutton">17</div>
<div class="golfcoursebutton">18</div>
</div>
</div>
</div>
</div>
EDIT
UPDATED WITH SOLUTION
querySelectorAll does not returns an array, so it doesn't have a forEach. Luckily, you can easily create an array out of it with Array.from:
// change this
clickOnMe.forEach(...
// to this
Array.from(clickOnMe).forEach(...
You're selecting the first of the document
document.querySelector(".subnav-content");
when it should be the first of the element
e.querySelector(".subnav-content");
I've created a template part in PHP that copies a button to each slide in a carousel using fullpage.js.
Unfortunately, your code re-use is throwing an error. If we look at your source, we see:
div.jump-button
button.course-button
div.subnav-content
<script>
const clickOnMe = ...
</script>
This is repeated ~20 times.
The issue is that const can only be declared once. After that, JS will throw an error. In fact, if we view the console, we see just that:
Basically, after the first declaration of const clickOnMe, an error is thrown after. That's why only the first one works. I would look into moving (and consolidating) the <script> where you define clickOnMe to the bottom and invoke that once all the HTML is loaded.
Edit:
Regarding your comment, I see what you're referring to. You're now querying all the elements correctly by moving the event binding to the bottom (awesome!), but your event listener will need to be updated as well. The change is actually answered here (by #jeyko-caicedo) by referring to the event object when toggling the classList.
A more complete answer would be that you need to reference the event object (to reference the clicked element) and then query the sibling subnav-content. One way is what jeyko suggested (via closure of the forEach). The other is in the event handler with either: 1 walking up the DOM tree (using e.currentTarget.parentNode) or 2: just reference the element directly like e.currentTarget.nextElementSibling.
let clickOnMe = document.querySelectorAll(".course-button");
Array.from(clickOnMe).forEach(function(el) { // updated `e` to `el`
el.addEventListener("click", (e) => {
let showBox = e.currentTarget.nextElementSibling;
showBox.classList.toggle("open-nav");
});
});
querySelectorAll returns a NodeList. It's essentially just an Array of DOM Nodes, but it doesn't support all of the Array methods that you'd expect it to have. You'll have to cast it to an array first, or manually for loop over it instead of using forEach.
I have several boxes of cards on one page, these boxes can come dynamically in different, not upper right corner has a text for the click to open the accordion type content, for each class I have to do an action as below, I think of something Regardless of the number of classes.
*new
I do not know how to explain it, I'll try a summary:
Change the text of only one div when clicking, because when I click on the item in the box it changes all the other texts of the
Other boxes.
$('.change-1').click(function () {
var $mudartxt = $('.mudartexto');
if ($mudartxt.text() == 'expandir')
$mudartxt.text('ocultar');
else {
$mudartxt.text('expandir');
}
});
You need to find the current clicked item.
For that you can use the event object
$('.change-1').click(function (e) {
// Get current target as jquery object
var $target = $(e.currentTarget);
// Find mudartexto in current target.
var $mudartxt = $target.find('.mudartexto');
if ($mudartxt.text() == 'expandir')
$mudartxt.text('ocultar');
else {
$mudartxt.text('expandir');
}
});
.change-1 {
display:inline-block;
width:200px;
height:50px;
text-align: center;
background-color:#dfdfdf;
clear: both;
float: left;
margin-top:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="change-1">
<div class="mudartexto">expandir</div>
</div>
<div class="change-1">
<div class="mudartexto">expandir</div>
</div>
<div class="change-1">
<div class="mudartexto">expandir</div>
</div>
<div class="change-1">
<div class="mudartexto">expandir</div>
</div>
If you are asking how to change text of an element, inside a clicked box, this should do it.
$('.change-1').click(function () {
var $mudartxt = $(this).find('.mudartexto');
if ($mudartxt.text() == 'expandir')
$mudartxt.text('ocultar');
else {
$mudartxt.text('expandir');
}
});
I am building a website that expands horizontally as user takes action like http://portal.azure.com style. When they click a button(from a list) in one div, the details of the selected items appear in another div beside it. this can get really long and over flow the mother div.
I am looking for a way i can automatically scroll the page to the right most edge when a new div overflows.
layout
<div style="overflow-x: auto">
<div layout="row">
<div class="col" style="width: 400px">
</div>
//SHOWN DYNAMICALLY
<div class="col" style="width: 400px">
</div>
//SHOWN DYNAMICALLY
<div class="col" style="width: 400px">
</div>
//SHOWN DYNAMICALLY
<div class="col" style="width: 400px">
</div>
//SHOWN DYNAMICALLY
<div class="col" style="width: 400px">
</div>
</div>
</div>
As you can see above, the first div shows by default but the other divs appear based on user interaction.
By the time the 3 div appears, it overflows.
How can i scroll to the right edge anytime it over flows? (you should really check out http://portal.azure.com to see what im talking about)
PS: i am using AngularJS. I am not using jquery. But i dont mind including it if its the only option
You can use plain Javascript for keeping the scroll to right.
Something like this:
var myDiv = document.getElementById("row");
myDiv.scrollLeft = myDiv.scrollWidth;
You need to fire the above function every time you add a new div. That way it will always automatically be scrolled when divs are dynamically added.
You will need to hook up the DOMNodeInserted event on your container. The function will be called whenever a div is added to your row container. This way you will not have to change anything in your existing code.
Here is a very simple example with dynamically added divs:
var num = 1,
btn = document.getElementById('btn'),
row = document.getElementById("row");
scroller(); // fire teh scroller right away for initial scroll
// function to keep it scrolled towards right
// function scroller() { row.scrollLeft = row.scrollWidth; }
// edited to add simple animation
function scroller() {
var maxScroll = row.scrollWidth - row.clientWidth; // required to stop
row.scrollLeft += 2;
if (row.scrollLeft < maxScroll) {
timer = window.setTimeout(scroller, 1000 / 60);
}
}
// hook up event to call scroller whenever an element is dynamically added
row.addEventListener("DOMNodeInserted", scroller);
// for demo to simluate dynamically adding divs
btn.addEventListener("click", function() {
var newDiv = document.createElement("div");
newDiv.setAttribute("class", "col");
num += 1; newDiv.innerText = num;
row.appendChild(newDiv);
});
div[layout] {
width: 500px; height: 140px; white-space: nowrap;
overflow: hidden; overflow-x: auto;
}
div.col { height: 140px; width: 400px; display: inline-block; text-align:center; }
div { border: 1px solid red; }
<div id="row" layout="row"><div class="col">1</div></div>
<button id="btn">Add</button>
Edit: Added simple animation using setTimeout (in order to keep jQuery away). Ideally you should be using requestAnimationFrame or a suitable library if you are already using one.
Using the flexbox justify-content property, elements can be distributed evenly in their container. However, I want to animate their positions when a new element is inserted or an existing one is removed.
I only managed to animate the height of the elements so far. However, there is a jump at the end of the animation since the gaps around the removed element that got animated to height: 0 vanish. Analogously, when inserting an element there is a jump at the beginning of the animation.
Is it possible to make an animation from end to end with justify-content? Here is an example to play with. Using CSS transition is preferred.
The main problem is that the behavior you are getting is the expected one.
In the very same instant that card.remove() is executed the flexbox justify-content property need to adjust the gaps around the removed element (as you said). And, as Paulie D has pointed out, there is nothing to animate about.
The only solution I can think about is to skip the flex thing and use javascript to create the necessary gaps among the card elements.
Here I leave the snippet:
var animation_time = 500;
var column_height = $('.column').height();
var cards_height = $('.card').height();
var cards_number;
var cards_total_height;
var space_to_be_distributed;
var placeholder_height;
function updateSizes(cards_number)
{
cards_total_height = cards_number * cards_height;
space_to_be_distributed = column_height - cards_total_height;
placeholder_height = space_to_be_distributed / (cards_number + 1);
}
updateSizes($('.card').length);
$('.placeholder').height(placeholder_height);
$(document).on('click', '.card', function () {
var card = $(this);
card.animate({height: 0, opacity: 0}, animation_time, function () {
card.remove();
});
updateSizes($('.card').length - 1);
var placeholder = card.next();
$('.placeholder').not(placeholder).animate({height: placeholder_height}, animation_time);
placeholder.animate({height: 0}, animation_time, function () {
placeholder.remove();
updateSizes($('.card').length);
$('.placeholder').animate({height: placeholder_height}, animation_time);
});
});
$('a').click(function () {
var card = $('<div class="card">');
card.css({opacity: 0, height: 0})
.appendTo('.column')
.animate({height: 25, opacity: 1}, animation_time);
var placeholder = $('<div class="placeholder">');
placeholder.css({height: 0})
.appendTo('.column');
updateSizes($('.card').length);
$('.placeholder').animate({height: placeholder_height}, animation_time);
});
body, html, .column {
height: 100%;
margin: 0;
}
.column {
float: left;
width: 100px;
background: navy;
overflow: hidden;
}
.card {
height: 25px;
width: 100px;
background: grey;
}
.placeholder {
height: 25px;
width: 100px;
}
<html>
<head>
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
</head>
<body>
<div class="column">
<div class="placeholder"></div>
<div class="card"></div>
<div class="placeholder"></div>
<div class="card"></div>
<div class="placeholder"></div>
<div class="card"></div>
<div class="placeholder"></div>
</div>
Add card
</body>
</html>
Hope it helps!
EDIT - I made the following changes in the code:
I change the fiddle for a SO snippet.
I forced an update of elements size at the end of the animation (in case you click to remove an element before the last one has been completely removed)
I change the size of the elementes to adapt it to the (small) SO snippet window.