My code runs below so that the correct div is appended to the page when I click the '.show-more' button. I want to be able to append 5 of these divs every time I click this button, but not sure how to do that?
HTML
<div class="content-section news-preview clearfix">
<div class="title">Title of News Article</div>
<div class="clearfix">
<div class="image-container">
<img src="images/news_sample208x135.jpg" width="208" height="135">
</div>
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Dui luctus lectus eget libero volupat, a tempor velit malesuada. Lorem ipsum dolor sit amet, conectetur adipiscing elit. Vivamus mattis egestas lorem a sodales.</p>
</div>
</div>
<a class="article-link">http://www.lintothenewsarticle.com/news/article/title-of-news-article</a>
</div>
<!-- /content-section -->
<div class="show-more-container">
<div id="content-news-container"></div>
<button class="btn show-more">Show 5 More</button>
</div>
jQuery
$('.show-more').click(function() {
var contentNews = $('div.content-section:last').prop('outerHTML');
console.log("contentNews", contentNews);
$('#content-news-container').append(contentNews).slideDown(slow);
});
You can use a DocumentFragment to append all of the elements in one go in an efficient manner
$('.show-more').click(function () {
var contentNews = $('div.content-section:last').prop('outerHTML');
var frag = document.createDocumentFragment();
for (var i = 0; i < 5; i++) {
frag.appendChild($(contentNews).get(0));
}
$('#content-news-container').append(frag).slideDown(slow);
});
EDIT: fiddle - http://jsfiddle.net/sc5585x7/
Just create a loop and clone the DIV five times:
$('.show-more').click(function () {
for (var i = 0; i < 5; i++) {
var contentNews = $($('div.content-section:last')[0].cloneNode(true));
$('#content-news-container').append(contentNews).slideDown('slow');
}
});
Fiddle here: http://jsfiddle.net/ToddT/364y88af/
EDIT:
As was pointed out, using a DocumentFragment is the more efficient way to do this sort of manipulation:
$('.show-more').click(function () {
var contentNews = $('div.content-section:last').prop('outerHTML');
var frag = document.createDocumentFragment();
for (var i = 0; i < 5; i++) {
frag.appendChild($(contentNews).get(0));
}
$('#content-news-container').append(frag).slideDown(slow);
});
Per #Travis Kaufman's answer.
Related
I'm getting an HTML I need to parse it so that I can read text under a certain Heading. More specifically, there is a div tag that includes several H2 elements and I need to read only the text between the 3rd and 4th H2 heading, i.e. the Summary section.
<div>
<h2>Risks</h2>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
<p>Donec fermentum orci nec felis.</p>
<h2>Affected Systems</h2>
<p>Sed sollicitudin diam id sapien.</p>
<p>Ut libero.</p>
<h2>Summary</h2>
<!-- from here -->
<p>Vestibulum quam libero, malesuada et, ornare id, aliquet id, tellus.</p>
<p>Nullam dapibus viverra quam.</p>
<p>Vestibulum sit amet nunc vel justo dictum pharetra.</p>
<!-- through here -->
<h2>Avoidance</h2>
<p>Proin eleifend mi eget massa.</p>
<p>Pellentesque feugiat sapien a ante.</p>
</div>
Good question. You can use a recursive function well for that. The function gets the start point (third h2) and the end point (fourth h2). Then you iterate over every single element within these two points. I have now written the output to the console. But you can concatenate it into a string.
function getTextFromTo(rootNode, startNode, endNode) {
let pastStartNode = false, reachedEndNode = false, textNodes = [];
function getTextNodes(node) {
if (node == startNode) {
pastStartNode = true;
} else if (node == endNode) {
reachedEndNode = true;
} else if (node.nodeType == 3) {
if (pastStartNode && !reachedEndNode && !/^\s*$/.test(node.nodeValue)) {
textNodes.push(node);
}
} else {
for (var i = 0, len = node.childNodes.length; !reachedEndNode && i < len; ++i) {
getTextNodes(node.childNodes[i]);
}
}
}
getTextNodes(rootNode);
return textNodes;
}
const from = document.querySelector('div :nth-child(5)'); // from
const to = document.querySelector('div :nth-child(11)'); // to
const root = document.querySelector('div');
var textNodes = getTextFromTo(root, from, to);
for (let i = 0, len = textNodes.length, div; i < len; ++i) {
console.log(textNodes[i].data)
}
<div class="col-md-12">
<h2>title 1</h2>
<ul><li></li></ul>
<h2>title 2</h2>
<ul><li></li></ul>
<h2>Resume</h2>
<p>text 1</p>
<p>text 2</p>
<p>text 3 this one</p>
<p>text 4</p>
<p>text 5 this one</p>
<h2>next title</h2>
</div>
The originator of this cool function is #TimDown. I just adapted it. How can I find all text nodes between two element nodes with JavaScript/jQuery?
You can use regex for it
/(?<=<h2>Résumé<\/h2>)(.|\n)*?(?=<h2>)/g
This will get all the text after <h2>Résumé<\/h2>' till next <h2> tag.
I am using the following jQuery code to try to get the text inside the element and add it to my variable:
<script>
var title = $('h3').html();
alert(title);
</script>
However, my browser is alerting me 'undefined' instead of the value inside the tag. Any idea what I am doing wrong?
Here is the html section for reference:
<article>
<div class="row">
<div class="columns large-6 large-centered medium-8 medium-centered small-12">
<h3>This is the post title</h3>
<h4>written by <b>Myself</b></h4>
<section>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla lacinia urna sit amet convallis dictum. Curabitur non sodales orci. Praesent vel gravida felis. Cras ultricies velit mi, eget efficitur ipsum tempus nec.</p>
</section>
</div>
</div>
</article>
Thanks,
This is the solution using plain JavaScript; you don't actually need jQuery here.
var h3element = document.getElementsByTagName("h3")[0];
This returns an array of all h3 elements in the document, of which you'll take the 0th index. Then, simply access the innerHTML property:
var h3content = h3element.innerHTML;
A complete solution would look something like:
<script>
var title = document.getElementsByTagName("h3")[0].innerHTML;
alert(title);
</script>
Try to wait for your document to trigger the ready event, if your code is beyond your tag, for example in the header. And if you only need the text, use the text function in jQuery.
<script>
$(function() {
var title = $('h3').text();
alert(title);
});
</script>
Do something like:
alert(document.getElementsByTagName('h3')[0].innerHTML)
Please help me. I want to hide ext by clicking on link, but something is wrong
But I could write only this, and don't undertand why it's not working! Maybe there is another way to do it? It's every time fills the same function. to li1 li2func, therefore thereis li1
Link to jsfiddler
html:`
<div>
<div class="left">
<ul>
<li><a id="11" href="#">one</a></li>
<li><a id="12" href="#">two</a></li>
<li><a id="13" href="#">three</a></li>
</ul>
</div>
<div class="right">
<p id="1">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloremque, qui.
</p>
<p id="2">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repellendus reiciendis veritatis voluptatibus optio explicabo? Dignissimos ex amet mollitia doloribus a.
</p>
<p id="3">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Impedit porro quisquam harum nemo, vitae itaque.</p>
</div>
</div>`
JS code:
var el = document.getElementsByTagName("p");
var cs = document.getElementsByTagName("a");
if(el) {
for (i = 0; i < el.length; i++) {
td = cs[i];
(function (_td) {
td.addEventListener('click', function(){
console.log(_td);
console.log(i);
document.getElementsByTagName("div")[i].className += document.getElementsByTagName("div")[i].className ? ' invis' : 'invis';
});
})(td);
You have a few problems with your javascript. You should have noticed this error in your javascript console: "Uncaught TypeError: Cannot read property 'className' of undefined", which might have led you to discover that document.getElementsByTagName("div") is not the selector you should be using. You did the work to produce an array of p tags (inexplicably named el), but then didn't make any reference to that within the closure you built.
Here's one way to fix that problem: give your closure a second argument, and pass the p tag of the corresponding number (i) to the a tag to which you're binding the click handler. Then modify the className string of that element.
var el = document.getElementsByTagName("p");
var cs = document.getElementsByTagName("a");
if(el) {
for (i = 0; i < el.length; i++) {
td = cs[i];
ptag = el[i];
(function (_td,_el) {
td.addEventListener('click', function(){
console.log(_td);
console.log(i);
_el.className += _el.className ? ' invis' : 'invis';
});
})(td,ptag);
}
}
One other thing: you'll notice that console.log(i) always produces 3 because that i is not bound to the scope of the click handler, but rather the outer scope of the for loop, so when the user clicks on one of the a tags, the loop has already completed and i will always equal 3.
While you tagged jquery this is how can you do with jquery by using the index() of href's closest li
$('ul > li > a').on('click' , function(){
var ThisId = $(this).closest('li').index();
$('div.right > p:eq('+ThisId+')').slideToggle(100);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div class="left">
<ul>
<li><a id="11" href="#">one</a></li>
<li><a id="12" href="#">two</a></li>
<li><a id="13" href="#">three</a></li>
</ul>
</div>
<div class="right">
<p id="1">
1 Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloremque, qui.
</p>
<p id="2">
2 Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repellendus reiciendis veritatis voluptatibus optio explicabo? Dignissimos ex amet mollitia doloribus a.
</p>
<p id="3">3 Lorem ipsum dolor sit amet, consectetur adipisicing elit. Impedit porro quisquam harum nemo, vitae itaque.</p>
</div>
</div>
document.getElementsByTagName will never return null, so if(el) in your code is unnecessary. An empty array will always evaluate to true. If you want i to not equal 3, then you have to add it to the closure at the moment it is 0, 1, and 2. I called it _index here:
var paragraphs = document.getElementsByTagName("p");
var links = document.getElementsByTagName("a");
for (i = 0; i < paragraphs.length; i++) {
link = links[i];
paragraph = paragraphs[i];
(function (_link,_paragraph, _index) {
_link.addEventListener('click', function(){
console.log(_link);
console.log(_index);
_paragraph.classList.toggle('invis');
});
})(link,paragraph, i);
}
Here is a cleaner version
function init(link, paragraph, index) {
link.addEventListener('click', function(){
paragraph.classList.toggle('invis');
});
}
var paragraphs = document.getElementsByTagName("p");
var links = document.getElementsByTagName("a");
for (i = 0; i < paragraphs.length; i++) {
init(links[i], paragraphs[i], i);
}
I have a question. Everything works fine, but if I add more tabs, so "isVisible" class is added to all other tabs. How do I fix this problem?
HTML:
<div class="content">
<button class="nextTab">Next Tab</button>
<div class="tabs">
<div class="tabs__item isActive">
<p>1 Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
</div>
<div class="tabs__item">
<p>2 Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
</div>
</div>
</div>
Javascript (Babel)
(() => {
const tabs = document.querySelector('.tabs')
, tabsItem = document.querySelectorAll('.tabs__item')
, nextTab = document.querySelector('.nextTab')
nextTab.addEventListener('click', () => {
for(let i = 0; i < tabsItem.length; i++) {
tabsItem[i].classList.toggle('isActive')
}
})
})()
You should track a current tab index in order to be able to switch to next one.
(() => {
const tabs = document.querySelector('.tabs')
, tabsItem = document.querySelectorAll('.tabs__item')
, nextTab = document.querySelector('.nextTab')
, currentTab = 0;
nextTab.addEventListener('click', () => {
if (++currentTab > tabsItem.length - 1) currentTab = 0;
document.querySelector('.isActive').classList.remove('isActive'));
tabsItem[currentTab].classList.add('isActive'))
});
})()
I want to remove Phase Content (1st header - See fiddle) and want only these in my code:
Expand - all steps
Steps 1
Steps 2
Steps 3
The above should appear without Phase Content in the code. But i dont know how to change the javascript so as to remove the Phase Content and work only with Steps Content
JSFIDDLE
or below is the code:
jQuery(".phaseContent").hide();
jQuery(".stepsContent").hide();
//toggle the componenet with phase level
jQuery(".phaseHeading .heading1").click(function () {
$(this).toggleClass("active");
var th = jQuery(this).parent();
jQuery(th).next(".phaseContent").slideToggle(500);
return false;
});
jQuery(".stepsHeading .heading1").click(function () {
$(this).toggleClass("active");
var th = jQuery(this).parent();
jQuery(th).next(".stepsContent").slideToggle(500);
return false;
});
//Expand and collapse toggle
$(".accordion-expand-all").click(function () {
var expandLink = $(this);
var contentAreas = $(expandLink).closest(".phaseContent").find(".stepsContent");
// Toggle the content area visibility
$(contentAreas).toggle();
// If the content area is now visible
if ($(contentAreas).is(':visible')) {
// Change it to the collapse text
$(expandLink).text('Collapse - all steps');
} else {
// Change it to the expand text
$(expandLink).text('Expand - all steps');
}
$(expandLink).closest(".phaseContent").find(".stepsHeading .heading1").toggleClass("active");
return false;
});
HTML
<!-- Start Phase -->
<!-- Start phase heading -->
<div class="phaseHeading"><span class="heading1">Phase 1</span>
</div>
<!-- Start phase content -->
<div class="phaseContent">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum laoreet, nunc eget laoreet sagittis, quam.
<!--Expand steps button-->
<p class="accordion-expand-holder">
<a class="accordion-expand-all" id="st1" href="#">Expand View - all steps</a>
</p>
<!-- Start steps heading -->
<div class="stepsHeading"><span class="heading1">Steps 1</span>
</div>
<div class="stepsContent">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum laoreet.
</div>
<!-- Start step 2 -->
<div class="stepsHeading"><span class="heading1">Steps 2</span>
</div>
<div class="stepsContent">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum laoreet, nunc eget laoreet sagittis.
</div>
<!-- Start step 2 -->
<div class="stepsHeading"><span class="heading1">Steps 3</span>
</div>
<div class="stepsContent">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum laoreet, nunc eget laoreet sagittis.
</div>
</div>
I update your Fiddle. Please check this jsFiddle
I remove phaseHeading from your HTML and put one Div above accordion-expand-holder name <div class="stepsParent">
<div class="stepsParent">
<p class="accordion-expand-holder"> <a class="accordion-expand-all" id="st1" href="#">Expand View - all steps</a>
</p>
<!-- Start steps heading -->
<div class="stepsHeading"><span class="heading1">Steps 1</span>
</div>
<div class="stepsContent">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum laoreet.</div>
<!-- Start step 2 -->
<div class="stepsHeading"><span class="heading1">Steps 2</span>
</div>
<div class="stepsContent">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum laoreet, nunc eget laoreet sagittis.</div>
<!-- Start step 2 -->
<div class="stepsHeading"><span class="heading1">Steps 3</span>
</div>
<div class="stepsContent">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum laoreet, nunc eget laoreet sagittis.</div>
</div>
Also change JS like Below
$(document).ready(function () {
$(".accordion-expand-all").parent().parent().find(".stepsContent").hide("slide");
jQuery(".stepsHeading .heading1").click(function () {
$(this).toggleClass("active");
var th = jQuery(this).parent();
jQuery(th).next(".stepsContent").slideToggle(500);
return false;
});
var collapsed = 1;
$(".accordion-expand-all").click(function () {
var expandLink = $(this);
var contentAreas = $(expandLink).parent().parent().find(".stepsContent");
if (collapsed == 0){
$(contentAreas).hide("slide");
collapsed =1;
$(expandLink).text('Expand - all steps');
} else {
$(contentAreas).show("slide");
collapsed = 0;
$(expandLink).text('Collapse - all steps');
}
$(expandLink).closest(".stepsHeading .heading1").toggleClass("active");
return false;
});
});
i have updated your jsFiddle, hope you get your solution.
changed javascript part
jQuery(".phaseHeading .heading1").click(function () {
$(this).toggleClass("active");
var th = jQuery(this).parent();
jQuery(th).next(".phaseContent").slideToggle(500);
jQuery(".phaseContent1").hide();
jQuery(".phaseHeading").hide();
return false;
});
changed html part
<div class="phaseContent1">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum laoreet, nunc eget laoreet sagittis, quam.
</div>
or you can also remove this changed div from html and jQuery(".phaseContent1").hide(); from changed js
You can use this
$(".phaseHeading .heading1").click(function () {
$(this).toggleClass("active");
var th = jQuery(this).parent();
$(th).next(".phaseContent").slideToggle(500);
$(".phaseContent1").hide();
$(".phaseHeading").hide();
return false;
});
Also do some changes in Div Class
<div class="Content1">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum laoreet.
</div>