jQuery wrap multiple elements independent of level - javascript

This is my first post on stackoverflow. So far I could always find an answer here, but this time I couldn't.
Here is my DOM structure:
<div id="elementA">
<div id="elementB"></div>
<div id="elementC">
<div id="elementD"></div>
</div>
<div id="elementE"></div>
</div>
How can I wrap 2 or more selected "random" elements into a wrapper container? This should also work if the selected elements are on different level and if there are other elements in between. The DOM structure of all other elements shouldn't be effected.
Following a few examples:
Example 1:
I though of something like this:
var element1 = $('#elementB');
var element2 = $('#elementE');
??? $(element1, element2).myWrap(".wrapper"); ???
Result should look like this:
<div id="elementA">
<div class="wrapper">
<div id="elementB"></div>
<div id="elementC">
<div id="elementD"></div>
</div>
<div id="elementE"></div>
</div>
</div>
2 Example:
Elements are in different levels.
var element1 = $('#elementD');
var element2 = $('#elementE');
??? $(element1, element2).myWrap(".wrapper"); ???
Result:
<div id="elementA">
<div id="elementB"></div>
<div class="wrapper">
<div id="elementC">
<div id="elementD"></div>
</div>
<div id="elementE"></div>
</div>
</div>
Example 3: More than 2 elements:
var element1 = $('#elementD');
var element2 = $('#elementC');
var element3 = $('#elementA');
??? $(element1, element2, element3).myWrap(".wrapper"); ???
<div class="wrapper">
<div id="elementA">
<div id="elementB"></div>
<div id="elementC">
<div id="elementD"></div>
</div>
<div id="elementE"></div>
</div>
</div>
Example 4: Different trees:
var element1 = $('#elementD');
var element2 = $('#elementF');
??? $(element1, element2).myWrap(".wrapper"); ???
<div id="elementA">
<div id="elementB"></div>
<div class="wrapper">
<div id="elementC">
<div id="elementD"></div>
</div>
<div id="elementE">
<div id="elementF"></div>
</div>
</div>
</div>

As was pointed out in the comments above, the first example is different to the others in that when the specified children are all direct decendants, then all children in the common parent should be wrapped.
Using this logic, the following solution works.
jQuery.fn.myWrap = function(options) {
var e = this;
// find most nested
var max = null;
var $mostNested = null;
$(e).each(function(i, elem) {
var parents = $(elem).parents().length;
if (parents > max || max == null) {
max = parents;
$mostNested = $(elem);
}
})
// find common parent
var found = false;
$parent = $mostNested.parent();
while($parent != null && !found) {
if ($parent.find(e).length == e.length) {
// Right Level
found = true;
var toWrap = [];
var numDirect = 0;
$.each($parent.children(), function(i, item) {
var direct = $(e).index(item) >= 0;
var sibling = $(item).find(e).length > 0;
if (direct) numDirect++;
if (direct || sibling) toWrap.push(item);
})
if (numDirect == e.length) {
// All direct! (Example 1)
$parent.children().wrapAll("<div class='wrapper'></div>");
} else {
// Other Examples
$(toWrap).wrapAll("<div class='wrapper'></div>");
}
}
$parent = $parent.parent();
}
};
$(document).ready(function() {
// Example 1
$('#elementB, #elementE').myWrap();
// Example 2
//$('#elementD, #elementE').myWrap();
// Example 3
//$('#elementD, #elementC, #elementA').myWrap();
// Example 4
//$('#elementD, #elementF').myWrap();
})
See my fiddle.

Related

Add an existing div element with classes (along with its underlying elements) to a div

I need to have a function that would add an existing div with a class (along with its underlying elements) to a particular div using for loop. It looks like this:
<div class="left-col">
<div class="list-row">
<div class="list-row2">
<span>Hello</span>
</div>
</div>
</div>
I need to loop through a function that will produce or duplicate "list-row" twice.
$(function() {
var leftcol = document.getElementsByClassName('left-col');
for (var i = 0; i < 2; i++) {
var listrow = document.querySelector('.list-row');
leftcol.appendChild(listrow[i]);
}
})
It should look like this:
<div class="left-col">
<div class="list-row">
<div class="list-row2">
<span>Hello</span>
</div>
</div>
<div class="list-row">
<div class="list-row2">
<span>Hello</span>
</div>
</div>
<div class="list-row">
<div class="list-row2">
<span>Hello</span>
</div>
</div>
</div>
You can try the following way:
$(function() {
var leftcol = document.querySelector('.left-col');
for (let i = 0; i < 2; i++) {
var listrow = document.querySelector('.list-row').cloneNode();
listrow.textContent = i + 1 + listrow.textContent;
leftcol.appendChild(listrow);
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="left-col">
<div class="list-row">0</div>
</div>
You could use cloneNode and set the deep property to true. This will clone the node and all of its descendants.
For example:
function cloneNode(copies = 1) {
for (let i = 0; i < copies; i++) {
let leftcol = document.getElementsByClassName('left-col')[0];
let nodeToClone = document.querySelector(".list-row");
let clonedNode = nodeToClone.cloneNode(true);
leftcol.appendChild(clonedNode);
}
}
clone.addEventListener("click", function() {
cloneNode();
});
<button id="clone" type="button">Clone Node</button>
<div class="left-col">
<div class="list-row">Test</div>
</div>
If you wanted to insert more than one copy, you could pass a different value to the cloneNode function.
You can use jQuery's .clone() method to copy the entire content of an element to another element. The boolean argument passed to the clone function determines whether the events associated with the cloned element has to be copied or not. true indicates all the events associated with that div has to be copied.
$(function() {
$('.list-row').each(function(){
$(".left-col").append($(this).clone(true));
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<div class="left-col">
<div class="list-row"><h1>This is original row</h1></div>
</div>
$(function() {
var leftcol = document.getElementsByClassName('left-col');
var listrow = document.querySelector('.list-row');
for (var i = 0; i < 2; i++) {
leftcol.appendChild(listrow.clone(true));
}
})

How to loop through JavaScript object in HTML?

I want to loop through a JavaScript object and repeat an html script as many times as the object length.
Here, I have the following in a script tag
<script>
var obj;
ipcRenderer.on('requests-results', (event, hosSchema) => {
obj = hosSchema
})
</script>
obj is an array retrieved from Mongo database as the picture below shows:
and I have the following inside <body> tag:
<div class="row">
<div class="col-md-4 col-sm-4">
<div class="card">
<div class="card-content">
<span class="card-title">.1.</span>
<p>.2.</p>
</div>
<div class="card-action">
.3.
.4.
</div>
</div>
</div>
</div>
How can I loop through obj to repeat the code between <div> tag as many times as obj.length?
I would suggest you to use Handlebars as #Amit mentioned.
first move out the code inside <div id="page-inner"> as below:
<div id="page-inner">
</div>
<script id= "requests-template" type="text/x-handlebars-template">
<div class="row">
{{#each requests}}
<div class="col-md-4 col-sm-4">
<div class="card">
<div class="card-content">
<span class="card-title">{{this.fieldName}}</span>
<p>{{this.fieldName}}</p>
</div>
<div class="card-action">
{{this.fieldName}}
{{this.fieldName}}
</div>
</div>
</div>
{{/each}}
</div>
</script>
Then inside another script page of type text/javascript you create the requests and assigned obj/hosSchema to it as below:
<script type="text/javascript">
var requestInfo = document.getElementById('requests-template').innerHTML;
var template = Handlebars.compile(requestInfo);
var requestData = template({
requests: obj
})
$('#page-inner').html(requestData);
</script>
NOTE: you need handlebars package installed (npm install handlebars --save)
Use templating script like Handlebars.js, Mustache.js or underscore.js.
Check below link for more description.
http://www.creativebloq.com/web-design/templating-engines-9134396
Try this:
var divlist = document.getElementsByTagName['div'];
var duplicate = null;
var rowIndex = -1;
var found = false;
for(var i = 0;i<obj.length;i++)
{
if(!found)
for(var p = 0;p<divlist.length;p++)
{
if(rowIndex != -1 && duplicate != null)
{
//set a Boolean to true and break
found = true;
break;
}
if(divlist[p].className == "col-md-4 col-sm-4")
{
//copy the element
duplicate = divlist[p];
}
else if(divlist[p].className == "row")
{
//identify the row's index
rowIndex = p;
}
}
//append the duplicate
divlist[rowIndex].appendChild(duplicate);
}

How to make controls of a customized javascript carousel

I'm making a customized javascript carousel . I would like to make controls for my carousel . I was searching for the answer but didn't find .
here is the code which I was working with
<div class="container">
<div class="row">
<div class="col-lg-6 top-space text-center float">
<h3 class="heading">Image Slider</h3>
<hr>
</div>
<div class="col-lg-6 float">
<img src="img/slider1.jpg" class="img-responsive" id="mainImage">
</div>
</div>
</div>
javascript code:
var imagesArray = ["img/slider2.jpg","img/slider3.jpg","img/slider4.jpg"];
var index = 0 ;
function imageSlider(){
var getImagePath = document.getElementById("mainImage");
getImagePath.setAttribute("src",imagesArray[index]);
index++;
if(index >= imagesArray.length){
index = 0;
}
}
setInterval(imageSlider,4000);
Here is the image:
Here is a example for you:
function imageSlider(){
this.prev = function(){
if(--this.index < 0) this.index = this.imagesArray.length - 1;
this.start()
};
this.next = function(){
if(++this.index >= this.imagesArray.length) this.index = 0;
this.start()
};
this.start = function(){
var getImagePath = document.getElementById("mainImage");
getImagePath.setAttribute("src", this.imagesArray[this.index]);
this.timeout && clearTimeout(this.timeout);
this.timeout = setTimeout(this.next.bind(this),3000)
};
}
var myCarousel = new imageSlider();
myCarousel.imagesArray = ["http://i.stack.imgur.com/d5vO7.jpg?s=128&g=1", "http://i.stack.imgur.com/GNgxX.png?s=128&g=1","http://i.stack.imgur.com/kpQYd.png?s=128&g=1"];
myCarousel.index = 0;
myCarousel.start()
<div class="container">
<div class="row">
<div class="col-lg-6 float">
<img src="img/slider1.jpg" class="img-responsive" id="mainImage">
<p><button onclick="myCarousel.prev()">Prev</button>
<button onclick="myCarousel.next()">Next</button></p>
</div>
</div>
</div>
First of all index should be increased before assigning the new path. After that, simply create a button that calls the imageSlider() function you have created and the slider should go an image forward. If you wan't to make it go backwards you'll have to create another function to do that. Something like:
var getImagePath = document.getElementById("mainImage");
index--;
getImagePath.setAttribute("src",imagesArray[index]);
if(index <= 0){
index = imagesArray.length - 1;
}
To implement the button functionality you can use the jQuery .click() method: https://api.jquery.com/click/
or use the Javascript only alternative: http://www.w3schools.com/jsref/event_onclick.asp

jquery filtered elements moved between divs

I'm bulding small filtering feature for items listed in div elements. These div elements are in a slider placed next to each other.
So each column contains a number of items. The filtering is working but i can't find a way to group the filtered items one under another so they would be in a first colum, not in their oryginal column:
<input id="filter" name="filter" size="40"/>
<div class="filtered">
<div class="archive-col-1 column">
<div class="name"><div class="element">Alchemy</div></div>
<div class="name"><div class="element">Balboa</div></div>
<div class="name"><div class="element">Nebula</div></div>
<div class="name"><div class="element">Radio</div></div>
</div>
<div class="archive-col-2 column">
<div class="name"><div class="element">Mathematics</div></div>
<div class="name"><div class="element">Disco</div></div>
<div class="name"><div class="element">Antwon</div></div>
<div class="name"><div class="element">Barracuda</div></div>
</div>
<div class="archive-col-3 column">
<div class="name"><div class="element">English</div></div>
<div class="name"><div class="element">France</div></div>
<div class="name"><div class="element">Nairobi</div></div>
<div class="name"><div class="element">Crazy</div></div>
</div>
</div>
function filter(element) {
$("#filter").keyup(function () {
var filter = $(this).val();
count = 0;
$(".column .element").each(function () {
var parent = $(this).parent();
var length = $(this).text().length > 0;
if (length && $(this).text().search(new RegExp(filter, "i")) < 0) {
parent.hide();
} else {
parent.show();
//appendTo.closest('.colums');
count++;
}
});
});
}
$('input').on('keyup change', function () {
filter(this);
});
example: http://jsfiddle.net/pw7k2/
In my another example filtering works fine but I don't know how to limit rows and move other filtered items to the next column, now they go to first column only:
http://jsfiddle.net/yQD7X/
Did anyone have similar problem?
http://jsfiddle.net/pw7k2/2/
function dispatchElements() {
var $elements = $('.column .element:visible').remove();
var $column = $('.column:first');
$elements.each(function(index, value) {
var height = $column.height();
var $childrens = $column.children(':visible');
var childrenHeight = 0;
$childrens.each(function(){
childrenHeight += $(this).outerHeight();
});
childrenHeight += childrenHeight/$childrens.length;
if (childrenHeight > height) {
$column = $column.next();
}
$(this).appendTo($column);
});
}
This method removes all visible elements and dispatch them after checking if there's available space in the current column, if not it takes the next one.

JQuery Sort Divs by child divs

I have the following list of divs and I'd like to be able to sort them using Javascript / JQuery.
<div class="item">
<div class="genre">Classical</div>
<div class="name">Alpha</div>
<div class="location">London</div>
</div>
<div class="item">
<div class="genre">Blues</div>
<div class="name">Bravo</div>
<div class="location">New York</div>
</div>
<div class="item">
<div class="genre">Pop</div>
<div class="name">Charlie</div>
<div class="location">Paris</div>
</div>
<div class="buttons">
Sort by Genre
Sort by Name
Sort by Location
</div>
I'd like to be able to sort the items by their Genre/Name/Location alphabetically.
Example: If Sort by Genre was clicked, it would sort the items in 0-9 A-Z by Genre.
If any of you have any tips it would greatly be appreciated.
Cheers :)
You have to make a little change to html like following:
<div id="container">
<div class="item">
<div class="genre">Classical</div>
<div class="name">Alpha</div>
<div class="location">London</div>
</div>
<div class="item">
<div class="genre">Blues</div>
<div class="name">Bravo</div>
<div class="location">New York</div>
</div>
<div class="item">
<div class="genre">Pop</div>
<div class="name">Charlie</div>
<div class="location">Paris</div>
</div>
</div>
<div class="buttons">
Sort by Genre
Sort by Name
Sort by Location
</div>
jQuery
function sorting(tag) {
var items = $('div.item').sort(function(a, b) {
var txt1 = $.trim($('div.' + tag, a).text()),
txt2 = $.trim($('div.' + tag, b).text());
if (txt1 > txt2) return 1;
else return -1;
});
return items;
}
$('.buttons a').on('click', function(e) {
e.preventDefault();
$('div#container').html(sorting(this.id));
});
Working Sample
Ok, this would be my pure JS solution.
First, we should wrap your <div>s into a larger container.
<div id = "wrapper">
<div id = "item">...</div>
<div id = "item">...</div>
<div id = "item">...</div>
</div>
Now, let's define a constant - which property do you want to sort it by? (this will probably be a function parameter later in your code).
var propName = "genre";
Let's get all the <div>s and put them in an array.
var items = document.getElementsByClassName("item");
var itemsArray = new Array();
Let us sort them lexicographically according to the text of the selected property.
for (var i = 0; i < items.length; i++)
itemsArray.push(items[i]);
itemsArray.sort(function(a, b) {
var aProp = a.getElementsByClassName(propName)[0].firstChild.nodeValue;
var bProp = b.getElementsByClassName(propName)[0] .firstChild.nodeValue;
if (aProp < bProp)
return -1;
else if (aProp > bProp)
return 1;
else
return 0;
});
Let us construct a document fragment consisting of the sorted <div>s.
var fragment = document.createDocumentFragment();
for (var i = 0; i < itemsArray.length; i++)
fragment.appendChild(itemsArray[i].clone());
Finally, let us clear the contents of the <div id = "wrapper"> and replace it with the document fragment.
document.getElementById('wrapper').innerHTML = '';
document.getElementById('wrapper').appendChild(fragment);
Also, note that document.getElementsByClassName does not work in IE<9, but I was now really lazy to cope with that issue.
A fiddle: http://jsfiddle.net/nNXr4/
Check this beast:
function sortByCreatedOnAsc(a,b){
return $(a).find('.created_on').text() > $(b).find('.created_on').text();
}
function sortByCreatedOnDesc(a,b){
return $(a).find('.created_on').text() < $(b).find('.created_on').text();
}
function reorderEl(el){
var container = $('#tasks');
container.html('');
el.each(function(){
$(this).appendTo(container);
});
}
$('#created_on').click(function(){
if($(this).hasClass("asc")){
reorderEl($('.task').sort(sortByCreatedOnDesc));
$(this).removeClass("asc");
$(this).addClass("desc");
} else {
reorderEl($('.task').sort(sortByCreatedOnAsc));
$(this).removeClass("desc");
$(this).addClass("asc");
}
return false;
});
jsfiddle: http://jsfiddle.net/jKJc3/116/

Categories