Cloning parent and its first + last child in jQuery - html

Say I have the following the markup:
$('button').click(function() {
let row = $('div.row');
let clonedRow = row.clone(true);
clonedRow.appendTo('body');
});
.row {
border: 1px solid black;
margin-bottom: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>append</button>
<div class="row">
<div class="first">append me!</div>
<div class="item">DONT append me</div>
<div class="item">DONT append me</div>
<div class="last">append me!</div>
</div>
I can achieve this by using clone() multiple times, but I'm looking for a clean solution that can do it with as little methods/functions as possible. Has to be in jQuery and not vanilla JS.

You can use the remove() method to remove the .item elements from the cloned content:
$('button').click(function() {
let $row = $('div.row:first').clone(true);
$row.find('.item').remove();
$row.appendTo('body');
});
.row {
border: 1px solid black;
margin-bottom: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>append</button>
<div class="row">
<div class="first">append me!</div>
<div class="item">DONT append me</div>
<div class="item">DONT append me</div>
<div class="last">append me!</div>
</div>

First you have to select row, then clone that row & then remove .items elements from that content by remove() method & then append that to the body.
$('button').click(function(e) {
e.preventDefault();
let row = $('div.row:first');
let clonedRow = $(row).clone(true);
$(clonedRow).find("div.item").remove();
$(clonedRow).appendTo('body');
});

Related

How to compare two classes with jquery?

I want to compare two classes if they're equal to display the content. I have three btns with three different classes and three other divs with three similar classes to buttons. I want to check if Over the button is equal to over the div,then i want to show the element inside over the div, and hide the other elements,and when i click on the under the button i want to do the same, I have tried with Jquery to compare to first get the class name from the button and get the class name from the div and compare them to each other and then give the active class to the one that i want to show it but it seems that i have something wrong
var className = $(this).attr('class');
var tabContent = $('.tab-content').hasClass(className);
var classNameBtnsName = $(this).hasClass(className);
$('button').click(function () {
if (tabContent === classNameBtnsName) {
$('.tab-content').addClass("active-content");
} else {
$('.tab-content').removeClass("active-content");
}
})
.active-content h1{
display:block;
}
h1{
display:none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="btns-container">
<button class="over">Over</button>
<button class="under">Under</button>
<button class="other">Other</button>
</div>
<div class="tab-content over active-content">
<h1 >Show Over elements</h1>
</div>
<div class="tab-content under">
<h1>Show Under elements</h1>
</div>
<div class="tab-content other">
<h1>Show Other Elements</h1>
</div>
I wouldn't use the class of the buttons to specify which content to toggle. It is better to use a data attribute for that to prevent future developments that add more classes to bug your functionality. Then you can use this data attribute for toggling by removing the active class from all and then adding the class to the element belonging to the clicked button.
$('button.togglebutton').on('click', (e) => {
$('.tab-content').removeClass('active-content');
$('.tab-content.' + $(e.currentTarget).data('active-content')).addClass('active-content');
});
.active-content h1 {
display: block;
}
h1 {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="btns-container">
<button data-active-content="over" class="togglebutton">Over</button>
<button data-active-content="under" class="togglebutton">Under</button>
<button data-active-content="other" class="togglebutton">Other</button>
</div>
<div class="tab-content over active-content">
<h1>Show Over elements</h1>
</div>
<div class="tab-content under">
<h1>Show Under elements</h1>
</div>
<div class="tab-content other">
<h1>Show Other Elements</h1>
</div>
Inside the click handler callback function, remove the active-content class from all .tab-content elements first, and then add it to the one that also has the button's class.
$('.btns-container button').on('click', function() {
$('.tab-content').removeClass('active-content');
$('.tab-content.' + this.className).addClass('active-content');
});
.active-content h1{
display:block;
}
h1{
display:none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="btns-container">
<button class="over">Over</button>
<button class="under">Under</button>
<button class="other">Other</button>
</div>
<div class="tab-content over active-content">
<h1 >Show Over elements</h1>
</div>
<div class="tab-content under">
<h1>Show Under elements</h1>
</div>
<div class="tab-content other">
<h1>Show Other Elements</h1>
</div>
Assuming .tab-content is hidden by default, you can try something like this:
$('button').click(function() {
// Get class from clicked button
var btnClass = $(this).attr('class');
$('.tab-content').each(function() {
// If tab-content has same class as button, show this
if ($(this).hasClass(btnClass)) {
$(this).show();
} else {
$(this).hide();
}
});
});

Aligning key colon value data in css without using HTML table?

I have the following data that I want to show.
Ideally I want the keys and values left aligned, separated with colons in the middle.
I want the result to be like the following:
key1 : value1
key2 : value2
keyAbc: Value Abc
key_N : value N
And not like the following:
key1: value1
key2: value2
keyAbc: Value Abc
key_N: value N
How to do this in CSS or SCSS, and not using HTML table?
You can use grid, making the columns take on the max width of content.
This snippet adds the colons in a pseudo element as they seem to be just a visual clue rather than part of the data.
Of course you will want probably to add some padding to suit your particular requirements.
.table {
display: grid;
grid-template-columns: max-content max-content;
}
.table > *:nth-child(even)::before {
content: ":";
}
<div class="table">
<div>key1</div>
<div>value1</div>
<div>key2222222</div>
<div>value2</div>
<div>key3</div>
<div>value3</div>
</div>
Just use the inline-block and make sure the children of the main DIV gets that too and it will automatically resize based on widest width, much like table. No need for flex.
.inline-block {
display: inline-block;
}
.inline-block > div {
margin: 2px;
padding: 1px;
}
<div class="inline-block">
<div>key1</div>
<div>keykey2</div>
<div>key3</div>
</div>
<div class="inline-block">
<div>:</div>
<div>:</div>
<div>:</div>
</div>
<div class="inline-block">
<div>value1</div>
<div>value2</div>
<div>Value3</div>
</div>
If you're using div structure, you can use display: flex and could do something like this:
.css-table {
display: flex;
}
.key {
width: 10%;
}
.val::before {
content: ': ';
}
<div class="css-table">
<div class="key">key1</div>
<div class="val">value1</div>
</div>
<div class="css-table">
<div class="key">key2111</div>
<div class="val">value2</div>
</div>
<div class="css-table">
<div class="key">key3</div>
<div class="val">value3</div>
</div>
<div class="css-table">
<div class="key">key4</div>
<div class="val">value4</div>
</div>
If you don't want to specify width, you'll need use JavaScript to calculate the width and apply it inline.
let maxWidth = 0;
// Calculate maxWidth
document.querySelectorAll('.css-table').forEach(function(cssTableEl) {
cssTableEl.querySelectorAll('.key').forEach(function(keyEl) {
let currWidth = keyEl.clientWidth;
if (currWidth > maxWidth) {
maxWidth = currWidth;
}
});
});
// Apply maxWidth
document.querySelectorAll('.css-table').forEach(function(cssTableEl) {
cssTableEl.querySelectorAll('.key').forEach(function(keyEl) {
keyEl.style.width = maxWidth + 'px';
});
});
.css-table {
display: flex;
}
.val::before {
content: ': ';
}
<div class="css-table">
<div class="key">key1</div>
<div class="val">value1</div>
</div>
<div class="css-table">
<div class="key">key2111</div>
<div class="val">value2</div>
</div>
<div class="css-table">
<div class="key">key3</div>
<div class="val">value3</div>
</div>
<div class="css-table">
<div class="key">key4</div>
<div class="val">value4</div>
</div>

Animate div's height with nested divs

Here is the snippet: https://jsfiddle.net/wc48jvgt/69/
I have a horizontally shaped div #cleaning_card_1, which has embedded divs which act like borders and vertical div #cleaning_card_right_1 with a nested div #cleaning_card_right_content_1. Inside the last div I have multiple divs which amount is dynamic. What I want to achieve is #cleaning_card_right_1 acting like a dropdown menu. I have a simple function to achieve that:
function maximizeCleaningCard () {
var cleaning_card_number = $(this).attr('number')
$(this).animate({width: '97%'}, 200, function () {
$('#cleaning_card_right_' + cleaning_card_number).removeClass('cleaning_card_right').addClass('cleaning_card_right_maximized')
$('#cleaning_card_right_' + cleaning_card_number).animate({height: 400}, 400)
$('#cleaning_card_right_content_' + cleaning_card_number).animate({height: 400 - 80}, 400)
$('#cleaning_card_right_left_border_1, #cleaning_card_right_right_border_1').animate({height: 400 - 80}, 400)
})
}
$('.cleaning_card').click(maximizeCleaningCard)
Animation is properly run on #cleaning_card_1 and border divs, however the #cleaning_card_right_content_1 is not animated at all. It just pops up there and thats it. If I'll remove nested items out of it, animation will properly work. I think that the problem is that div's height is not equal to 0 due to nested elements, but most likely I am mistaken. How to overcome this issue?
I noticed you are animated multiple divs to get the simultaneous vertical animate. You could streamline your div layout to get the same effect by just using 2 animates to complete the sequence.
I've removed all the unnecessary divs and used more practical css to get the same effect. Might not be perfect for your final use but may get you on the right track.
I've also added a minimizing sequence using the class .maximized to tell what state the cleaning card is in, and which sequence to run.
Here is a fiddle too https://jsfiddle.net/joshmoto/0ynrm1ts/2/
See comments in my script to see what is happening...
// maximize cleaning card
function maximizeCleaningCard() {
// store current clicked cleaning card variable for later use in animate
let cleaningCard = this;
// set cleaning card right element variable
let cleaningCardRight = $('.cleaning_card_right', cleaningCard);
// check we actually have a cleaning card right
if($(cleaningCardRight).length) {
// set the cleaning card right content variable
let cleaningCardRightContent = $('.cleaning_card_right_content', cleaningCardRight);
// if cleaning card has maximized class
if($(cleaningCard).hasClass('maximized')) {
// remove the maximized class
$(cleaningCard).removeClass('maximized');
// animate cleaning card right first to reverse sequence
$(cleaningCardRight).animate({
height: '0px'
}, 500, function() {
// when cleaning card right is fully closed
// animate cleaning card to finish the closing sequence
$(cleaningCard).animate({
width: '70%'
}, 500 );
});
// else if cleaning card does not have maximized class
} else {
// add the maximized class
$(cleaningCard).addClass('maximized');
// animate cleaning card width to 100%
$(cleaningCard).animate({
width: '100%'
}, 500, function() {
// when cleaning card is fully open
// animate cleaning card height to the cleaning card right content
$(cleaningCardRight).animate({
height: $(cleaningCardRightContent).outerHeight()
}, 500 );
});
}
}
}
// when cleaning card is clicked
$(document).on('click','.cleaning_card', maximizeCleaningCard );
BODY {
padding: 15px;
margin: 0;
}
.cleaning_card {
position: relative;
width: 70%;
border: 1px solid black;
height: 80px;
font-size: 15px;
overflow: visible;
margin-bottom: 15px;
}
.cleaning_card:hover {
cursor: pointer;
}
.cleaning_card_right {
position: absolute;
width: 25%;
height: 0;
background-color: white;
border-bottom: 1px solid black;
border-left: 1px solid black;
border-right: 1px solid black;
overflow: hidden;
top: 100%;
right: -1px;
}
.cleaning_card_right_content {
position: relative;
padding: 5px;
overflow: hidden;
}
.cleaning_card_right_content_item {
position: relative;
background-color: cornsilk;
}
<div id="cleaning_card_1" class="cleaning_card">
<div class="cleaning_card_right">
<div class="cleaning_card_right_content">
<div class="cleaning_card_right_content_item">
<div class="cleaning_card_right_category"> Standard </div>
<div class="cleaning_card_right_value"> 1 </div>
</div>
<div class="cleaning_card_right_content_item">
<div class="cleaning_card_right_category"> Junior Suite </div>
<div class="cleaning_card_right_value"> 2 </div>
</div>
<div class="cleaning_card_right_content_item">
<div class="cleaning_card_right_category"> Lux </div>
<div class="cleaning_card_right_value"> 3 </div>
</div>
</div>
</div>
</div>
<div id="cleaning_card_2" class="cleaning_card">
<div class="cleaning_card_right">
<div class="cleaning_card_right_content">
<div class="cleaning_card_right_content_item">
<div class="cleaning_card_right_category"> Standard </div>
<div class="cleaning_card_right_value"> 1 </div>
</div>
<div class="cleaning_card_right_content_item">
<div class="cleaning_card_right_category"> Junior Suite </div>
<div class="cleaning_card_right_value"> 2 </div>
</div>
<div class="cleaning_card_right_content_item">
<div class="cleaning_card_right_category"> Lux </div>
<div class="cleaning_card_right_value"> 3 </div>
</div>
</div>
</div>
</div>
<div id="cleaning_card_3" class="cleaning_card">
<div class="cleaning_card_right">
<div class="cleaning_card_right_content">
<div class="cleaning_card_right_content_item">
<div class="cleaning_card_right_category"> Standard </div>
<div class="cleaning_card_right_value"> 1 </div>
</div>
<div class="cleaning_card_right_content_item">
<div class="cleaning_card_right_category"> Junior Suite </div>
<div class="cleaning_card_right_value"> 2 </div>
</div>
<div class="cleaning_card_right_content_item">
<div class="cleaning_card_right_category"> Lux </div>
<div class="cleaning_card_right_value"> 3 </div>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

jquery ui resizable with .each() works only on first child

This is the initial html which has 'n' no. of child elements with same class name.
<div class="reading-content">
<div class="c-resourceitem-content">
<div data-id="1" class="resource"></div>
<div class="btn" id="btn"></div>
</div>
<div class="c-resourceitem-content">
<div data-id="2" class="resource"></div>
<div class="btn" id="btn"></div>
</div>
<div class="c-resourceitem-content">
<div data-id="3" class="resource"></div>
<div class="btn" id="btn"></div>
</div></div>`
Javascript: Appending a div as a handler which resizes the element vertically
$('.reading-content').children('.c-resourceitem-content').each(function eachFn() {
$(this).children().wrapAll("<div class='resourceitem-content-wrap'></div>");
var id = $(this).children("resource").attr('id');
ResourceSplitter = $('<label class="resource-splitter ">'+'</label>').attr("id", "id_" + id);
$( ResourceSplitter).appendTo($(this));
$(this).resizable({
handles: { 's' : '.resource-splitter' }
});
});
The final html snippet looks like this by wrapping all child div and appending a handler for resizing as per need .
<div class="reading-content">
<div class="c-resourceitem-content">
<div class="resourceitem-content-wrap">
<div data-id="1" class="resource"></div>
<div class="btn" id="btn"></div>
</div>
<label class="resource-splitter" id="id_1"></label>
</div>
</div>
But the problem is that resizing happens only for the first child element with the class 'c-resourceitem-content' inside the .each() function.
Please do help me out with a solution so that all the child classes are resizable by using the handler appended to each div.
CSS:
.resourceitem-content-wrap{
overflow-y:auto;
overflow-x: hidden;
width:100%;
height:100%;
}
.resource-splitter{
background:#ccc;
height:5px;
border-left:none;
display:block;
flex: 0 0 auto;
cursor: row-resize;
z-index: 80;
}
.reading-content {
height:auto;
margin-top: 15px;
margin-right: 15px;
}
Noticed with the code provided the id applied to the resource-splitter is undefined. Using the index value on the .each function will remove the need for this code:
var id = $(this).children("resource").attr('id');
The index will enumerate over each c-resourceitem-content, I've added an id variable that starts from 1. Like below:
$(".reading-content")
.children(".c-resourceitem-content")
.each(function eachFn(index) {
let id = index + 1;
$(this)
.children()
.wrapAll("<div class='resourceitem-content-wrap'></div>");
ResourceSplitter = $(
'<label class="resource-splitter ">' + "</label>"
).attr("id", "id_" + id);
$(ResourceSplitter).appendTo($(this));
$(this).resizable({
handles: { 's': ".resource-splitter" }
});
});
Are you able to provide the styling applied to the html so I can test it further?

smooth scroll with mousewheel to next or previous div

I'm trying to get a javascript on my site so when a person scrolls on the website, it automatically scrolls to the next or previous Div with a certain class. I'm working with smoothscroll and scrollto. I also found two codes that I'm trying to combine. But I don't seem to understand the whole scripts...
The first script is from http://webdesignerwall.com/tutorials/scrollto-posts-with-jquery. This script makes it possible to navigate between DIV's (with a certain class) by pressing next or previous.
The second script is from How to enforce a "smooth scrolling" rule for mousewheel, jQuery? (last post) and makes it possible to make the website scroll (smooth) down or up for a certain amount of pixels when scrolling.
I wanted to combine these two but it's not really straight forward for me :/
It would be nice if someone could point me how to do this. Thanks
Best regards,
Billy Beach
Dear lalibi,
Thanks for your answer. I tried your code, but don't seem to get it work. Here is the code I used:
<head>
<script type="text/javascript" src="Box/jquery.js"></script>
<SCRIPT src="Box/jquery.min.js"></SCRIPT>
<SCRIPT src="Box/jquery.scrollTo-1.4.2-min.js"></SCRIPT>
<SCRIPT src="Box/jquery.localscroll-1.2.7-min.js"></SCRIPT>
<script type="text/javascript" src="Box/jquery.mousewheel.min.js"></script>
<style type="text/css">
<!--
div {
border: 1px solid black;
height: 50px;
}
div.current {
background-color: orange;
}
-->
</style>
<script type="text/javascript">
var current
$(function() {
$('body').mousewheel(function(event, delta) {
var $current = $('div.current');
console.log(delta);
console.log($current);
if (delta > 0) {
$prev = $current.prev();
if ($prev.length) {
$('body').scrollTo($prev, 100);
$current.removeClass('current');
$prev.addClass('current');
}
} else {
$next = $current.next();
if ($next.length) {
$('body').scrollTo($next, 100);
$current.removeClass('current');
$next.addClass('current');
}
}
event.preventDefault();
});
});
</script>
</head>
<body>
<div class="current" id="div">1</div>
<div id="div">2</div>
<div id="div">3</div>
<div id="div">4</div>
<div id="div">5</div>
<div id="div">6</div>
<div id="div">7</div>
<div id="div">8</div>
<div id="div">9</div>
<div id="div">10</div>
<div id="div">11</div>
<div id="div">12</div>
<div id="div">13</div>
<div id="div">14</div>
<div id="div">15</div>
<div id="div">16</div>
<div id="div">17</div>
<div id="div">18</div>
<div id="div">19</div>
<div id="div">20</div>
<div id="div">21</div>
<div id="div">22</div>
<div id="div">23</div>
<div id="div">24</div>
<div id="div">25</div>
<div id="div">26</div>
<div class="current" id="div">27</div>
<div id="div">28</div>
<div id="div">29</div>
<div id="div">30</div>
<div id="div">31</div>
<div id="div">32</div>
<div id="div">33</div>
<div id="div">34</div>
<div id="div">35</div>
<div id="div">36</div>
<div id="div">37</div>
<div id="div">38</div>
<div id="div">39</div>
<div id="div">40</div>
<div id="div">41</div>
<div id="div">42</div>
<div id="div">43</div>
<div id="div">44</div>
<div id="div">45</div>
<div id="div">46</div>
<div id="div">47</div>
<div id="div">48</div>
<div id="div">49</div>
<div id="div">50</div>
<div id="div">51</div>
<div id="div">52</div>
<div id="div">53</div>
<div id="div">54</div>
<div id="div">55</div>
<div id="div">56</div>
<div class="current" id="div">57</div>
</body>
</html>
EDIT: I tweaked the fiddle a little bit. One of the two external scripts was using http: and since the link (before the edit) used https:, Chrome blocked it unless you pressed the little shield icon. I also updated to latest version.
This seems to work fine: http://jsfiddle.net/9Amdx/1707/
var current;
$(function() {
$('body').mousewheel(function(event, delta) {
var $current = $('div.current');
console.log(delta);
console.log($current);
if (delta > 0) {
$prev = $current.prev();
if ($prev.length) {
$('body').scrollTo($prev, 100);
$current.removeClass('current');
$prev.addClass('current');
}
} else {
$next = $current.next();
if ($next.length) {
$('body').scrollTo($next, 100);
$current.removeClass('current');
$next.addClass('current');
}
}
event.preventDefault();
});
});