Basic jQuery carousel from scratch - javascript

I would use one of the readily available jQuery plugins, but none of them fit my needs for this particular site.
This is the code that I have so far:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"></script>
<script type="text/javascript" src="js/pushState.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#nav a.slide").click(function() {
var img = $(this).children('img').attr('src');
$('#content').hide().css({ 'background':'url('+ img +') no-repeat 50% 50%' }).fadeIn('3000');
var remApp = $(this).prev('a.slide');
remApp.remove();
$("#nav").append(remApp);
});
});
</script>
<style type="text/css">
html, body {
padding: 0px;
margin: 0px;
}
#content {
position: absolute;
width: 100%;
height: 100%;
padding: 0px;
margin: 0px;
z-index: 1;
}
#nav {
position: absolute;
top: 70%;
z-index: 3;
}
#nav a.slide {
margin: 0 20px 0 0;
text-decoration: none;
}
#nav .slide img {
width: 100px;
height: 85px;
}
</style>
</head>
<body>
<div id="content">
</div>
<div id="social_links">
</div>
<div id="nav">
<a href="#" class="slide">
<img src="images/slide1.gif" />
</a>
<a href="#" class="slide">
<img src="images/slide2.jpg" />
</a>
<a href="#" class="slide">
<img src="images/slide3.jpg" />
</a>
<a href="#" class="slide">
<img src="images/slide4.jpg" />
</a>
<a href="#" class="slide">
<img src="images/slide5.png" />
</a>
</div>
</body>
</html>
This takes the image that you click on and removes it, then appends it to the end. I need it to take each of the previous images and append them.
Also, it seems to have a one-time rule. I can make each of the images go once, but then nothing happens.
You can see it in "action" here

There are two possible issues (solving one of them should help) resulting from the fact, that the events are bound to the elements, and when the elements are removed and added again, the events are not bound to the elements any more. In other words you remove the element from the DOM along with deleting the events attached, but when you insert them in the DOM again, the events are not re-attached.
There are two ways you can fix it:
do not attach events to the elements, but to the container, and then delegate the events (using jQuery's .delegate() function) to the elements you need, eg. like that:
$("#nav").delegate('a.slide', 'click', function() {
var img = $(this).children('img').attr('src');
$('#content').hide().css({ 'background':'url('+ img +') no-repeat 50% 50%' }).fadeIn('3000');
var remApp = $(this).prev('a.slide');
remApp.remove();
$("#nav").append(remApp);
});
when removing the elements, do it using .detach(), not .remove() jQuery's function - it will remove the elements without deleting the events. As .remove()'s documentation says:
Similar to .empty(), the .remove() method takes elements out of the
DOM. Use .remove() when you want to remove the element itself, as well
as everything inside it. In addition to the elements themselves, all
bound events and jQuery data associated with the elements are removed.
To remove the elements without removing data and events, use .detach()
instead.

Your event handlers are being removed from the slides when you use .remove. Per the jQuery documentation (emphasis mine):
Use .remove() when you want to remove the element itself, as well as everything inside it. In addition to the elements themselves, all bound events and jQuery data associated with the elements are removed. To remove the elements without removing data and events, use .detach() instead.
I wouldn't remove it or detatch it though. Just append it and jQuery will automatically put it at the end. Since you want to move all previous siblings to the end too, you want this:
var remApp = $(this).prev('a.slide');
$("#nav").append(remApp.prevAll().andSelf());
Note that I removed the .remove command and I added .prevAll().andSelf() to remApp. .prevAll() gets all previous siblings (but not remApp) and .andSelf() rejoins remApp to the collection. Then you append the whole collection to the end of the list.

Related

Using addEventListener

I'm trying to toggle a second element by clicking on the first, and not having the second as interactive but it's not working. What am I doing wrong? The element.timage should change itself and the element . rimage when selected, but only the element.timage should be clickable.
function myFunction(x) {
if (x.target.matches('.timage'))
this.classList.toggle('change');
}
document.querySelector('.container4').addEventListener('click', myFunction);
.container4 {
cursor: pointer;
display: inline- block;
}
.timage {
position: relative;
left: 50px;
}
.change .timage {
left: 200px;
}
.rimage {
position: relative;
left: 200px;
}
.change .rimage {
position: relative;
left 500px;
}
<a id="mobile-nav" href="#">
<div class="container4" onclick="myFunction
(this,event)">
<div class="container4">
<div class="timage"><img class="size-medium wp-
image-13846" src="http://4309.co.uk/wp-
content/uploads/2020/05/
IMG_20200509_104613-
288x300.jpg" alt="" width="70" height="300" />.
</div>
<div class="rimage">
<img class="size-medium wp-
image-13669" src="http://4309.co.uk/
wp-content/uploads
/2020/05/IMG_20200508_1
30758-287x300.jpg" alt="" width="90" height="300" />.
</div>
</div>
</a>
You're probably clicking the img, not the div that the image is in, so event.target is the img.
To find the nearest ancestor (starting with the current element) that matches a selector, use closest.
You're also using myFunction both in onclick="myFunction(this,event)" and in an addEventListener call. Those will provide different arguments to the function. Remove the onclick and just use addEventListener.
Here's the updated function:
function myFunction(x) {
const timage = x.target.closest(".timage");
if (timage && this.contains(timage)) {
this.classList.toggle('change');
}
}
The reason for the contains is just completeness and in many cases you can leave it off: It's to defend against closest having gone past the container element and found the match in the container's ancestors. That won't happen with your layout because timage is only used with the container, but for more general situations, I include that check. For instance:
<div class="x">
<div id="container">
<div class="x">xxx</div>
<div class="y">yyy</div>
</div>
</div>
There, if I have click hooked on #container and the user clicks yyy and I'm doing const x = event.target.closest(".x"), I'll get the .x that's the parent of the container. So this.contains(x) weeds those out.

Showing text upon a click

I am attending an entry level HTML/CSS/JS course and our first assignment is to make a simple website about ourselves. We need to have a horizontal menu that when clicked displays certain information. For example, clicking "description" should display a short paragraph describing ourselves. From what I've researched it seems that my answer lies with using JQuery but I don't believe he expects us to know that nor utilize it this early. Is there another option that I may not be seeing?
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="style.css">
<title>Jeremy Ortiz</title>
<div id="header">
<h1>A Little About Jeremy Ortiz</h1>
</div>
</head>
<body>
<img src="hwpic.jpg" alt="Me">
<div id="content">
<div id="nav">
<h2>Navigation</h2>
<ul>
<li><a class="selected" href="">Description</a></li>
<li>A form</li>
<li>Course List</li>
<li>Table</li>
<li>Contact Information</li>
</ul>
</div>
</body>
</html>
#header {
padding: 10px;
background-color: #6CF;
color: white;
text-align: center;
}
img {
position: absolute;
right: 7px;
bottom: 148px;
z-index: -1;
}
#content {
padding: 10px;
}
#nav {
width: 180px;
float: left;
}
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
My answer will assume your goal is to accomplish this task using basic Javascript instead of changing pages by navigating the user using the <a> elements. I understand that there are more efficient methods of performing this but I chose to present the information in a hopefully simple easily readable manner.
The way I would accomplish this is by changing your <a> elements:
<a class="selected" href="">Description</a>
To button elements and add the 'onclick' property with the function to call when the button is clicked:
<button onclick="displayDescription()">Click Me</button>
Now we need to create the elements that will be displayed upon clicking the button. For this we create some <div> other container that we can hide until the corresponding button is clicked.
<div id="description" style="display: none;">
Displayed when the description button is clicked.
</div>
Note** For every button we will need to create a <div style="display: none;"> to hide the information until its corresponding button is clicked.
Now we can create our Javascript function:
function displayDescription() {
var x = document.getElementById('description');
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
Note once again that in this method each Javascript function will map to a button in the same way each hidden will map to the same button.
If you need more help I recommend checking out w3schools and specifically for this problem here is a link to what you need to accomplish with your assignment.
http://www.w3schools.com/howto/howto_js_toggle_hide_show.asp
I hope this was helpful as I just wrote this during one of my college classes I will probably formalize my answer more at a later time today.

How could I make this tab controller code cleaner and simpler?

How would I be able to simplify this jquery code. I feel like I am repeating myself and just wondering if there is a shorter way to write this which I'm sure there is. I am a bit new to javascript and jquery. I have created a two tabs with their own containers with miscellaneous information in them. Basically I want the container to open when it's related tab is clicked on. I also would like the tab to be highlighted when it's active. Also, how would I be able to write code to make all tab containers disappear when you click off from the tab containers.
<!-- HTML Code -->
<div class="sort-filters">
<span class="sort-by active">SORT BY</span>
<span class="filter">FILTER</span>
</div>
<div class="sort-containers">
<div class="sort-by-container">Sort by click me here</div>
<div class="filter-container">Filter click me here</div>
</div>
/* CSS */
.sort-filters {
display: flex;
width: 500px;
height: 30px;
}
.sort-by,
.filter {
background: #CCC;
color: #756661;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Arial', sans-serif;
cursor: pointer;
}
.sort-by-container,
.filter-container {
width: 500px;
background: #756661;
color: #FFF;
height: 100px;
display: none;
}
.active {
background: #756661;
color: #FFF;
transition: 0.2s;
}
// Jquery Code
js = $.noConflict();
var sort = js('.sort-by');
var filter = js('.filter');
var sortContainer = js('.sort-by-container');
var filterContainer = js('.filter-container');
js(sort).click(function() {
js(filterContainer).hide();
js(sortContainer).show();
js(sort).addClass('active');
js(filter).removeClass('active');
});
js(filter).click(function() {
js(sortContainer).hide();
js(filterContainer).show();
js(filter).addClass('active');
js(sort).removeClass('active');
});
In order to avoid such repetitive actions I like to stick to naming conventions, so that I can apply the ID's, classes or attributes from one element to select other elements, for instance:
<div id="tabs">
<span class="active" data-type="sort-by">SORT BY</span>
<span data-type="filter">FILTER</span>
</div>
Now, all you need is one click handler on #tabs span, and get the data-type of the span you clicked on. You can use that to filter on the classes of the other container elements.
The second thing is that you can attach handler to more than 1 element at the same time. So in your example, js('#sort-containers div').hide(); will hide all the div's that match the selector at once.
results
I changed some classes to ID's, and some classes to data attributes. Here's a fiddle: https://jsfiddle.net/mq9xk29y/
HTML:
<div id="tabs">
<span data-type="sort-by">SORT BY</span>
<span data-type="filter">FILTER</span>
</div>
<div id="sort-containers">
<div class="sort-by-container">Sort by click me here</div>
<div class="filter-container">Filter click me here</div>
</div>
JS:
js = $.noConflict();
var $tabs = js('#tabs span');
$tabs.click(function() {
var $clicked = js(this); //get the element thats clicked on
var type = $clicked.data('type'); //get the data-type value
$tabs.removeClass('active'); //remove active from all tabs
$clicked.addClass('active'); //add active to the current tab
js('#sort-containers div').hide(); //hide all containers
js('.' + type + '-container').show().addClass('active'); //add active to current container
});
As long as you follow the naming convention of data-type: bla in the tabs, and bla-container on the classes in sort-container, you never have to worry about coding for additional tabs.
There might still be things that could be further optimised, but at least it'll take care of the repetition.

Get place number of div using jquery

I have following slider code in html;
<div class="carousel-inner" style="position: relative;">
<div class="item">
<img src="forsidebanner_gf39.jpg" alt="">
<a class="overlay" style="position: absolute; top: 0%; left: 0%; width: 101.4%; height: 103.31491712707%;" href="domain.com" title="">
</a>
</div>
<div class="item active">
<img src="forsidebanner_50fifty_somvistpaafarmen.jpg" alt="">
<a class="overlay" style="position: absolute; top: 0%; left: 0%; width: 100.8%; height: 102.76243093923%;" href="domain.com/one.html" title="">
</a>
</div>
What I want to achieve is to console log the div number of class "item" so for example if clicked on image 1 of parent class "item" it will print 1, and if click on second image it will print 2.
I tried this code but its printing only 1
$(".item").click(function(){
var numitem = $(this).length;
console.log(numitem);
});
This is the demo link -> https://jsfiddle.net/ru44voeq/
Any help will be highly appreciated.
Thanks
The problem were the overlays. Because of that you could not retrieve the index of the clicked element. Since you can not hide them by removing the html the jquery then took care of that.
Because the overlays were hidden, you can not navigate to your URL. By retrieving the URL attribute
window.location.href = $(this).find(".overlay").attr("href");
from the overlay which is shown again that is made possible and the page is shown.
Full jquery code and example,
fiddle example: https://jsfiddle.net/eugensunic/ru44voeq/3/
$(".overlay").hide();
$(".item").click(function(){
var numitem = $(this).index()+1;
$(".overlay").show();
window.location.href = $(this).find(".overlay").attr("href");
alert(numitem);
});
Using the index() function work but the problem you have is the style of overlays like #GrafiCode Studio mentioned in comment, so when removing the style the link will not work, that true.
Try this solution that copy the img tag and remove the original and append the copy of the img to the link, it work see the code bellow.
//Restructuring the HTML code on ready
$(".carousel-inner").find('.item').each(function(){
//make a copy of img
var img = $(this).find('img').clone(true);
//remove image
$(this).find('img').remove();
//append copy to the link
$(this).find('a').removeAttr('style').html(img);
});
//Handle the click event
$(".item").click(function(){
var numitem = $(this).index()+1;
alert(numitem);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="carousel-inner" style="position: relative;">
<div class="item">
<img src="http://web.ccpgamescdn.com/newssystem/media/67432/1/100_-Twitter.jpg" alt="">
<a class="overlay" style="position: absolute; top: 0%; left: 0%; width: 101.4%; height: 103.31491712707%;" href="domain.com" title="">
</a>
</div>
<div class="item active">
<img src="http://www.elcomcms.com/Images/UserUploadedImages/664/facebookicon_100x100.jpg" alt="">
<a class="overlay" style="position: absolute; top: 0%; left: 0%; width: 100.8%; height: 102.76243093923%;" href="domain.com/one.html" title="">
</a>
</div>
</div>
Hope this helps.
You can use inArray function to solve this. Check it out the code below.
$(".item").click(function(){
console.log($.inArray(this,$(".item")));
});
Doing this, you will add to every item the click event. The function inArray works with a element on the first parameter, on this case the item, and a list of elements on the second parameter, this function will return the index of the item on the given array.
You are setting a click listener to each of the items.
When the callback function gets executed the context (what this refers to) is the clicked element, the node itself.
Then you call the jQuery function on the node with $(this) which returns you a jQuery element, with only that node in it.That's why length is 1.
If you want to get the number of the .item you should do something like:
var items = $('.item')
items.click(function (){
.....
items.length //number of items
$(this).index() //index of the node in its parent, not relative to the `.items`
var itemIndex = $.inArray(this, items) //as suggested by #Franklin Satler
})
The docs say:
Search for a specified value within an array and return its index (or -1 if not found).

How to move an element into another element

I would like to move one DIV element inside another. For example, I want to move this (including all children):
<div id="source">
...
</div>
into this:
<div id="destination">
...
</div>
so that I have this:
<div id="destination">
<div id="source">
...
</div>
</div>
You may want to use the appendTo function (which adds to the end of the element):
$("#source").appendTo("#destination");
Alternatively you could use the prependTo function (which adds to the beginning of the element):
$("#source").prependTo("#destination");
Example:
$("#appendTo").click(function() {
$("#moveMeIntoMain").appendTo($("#main"));
});
$("#prependTo").click(function() {
$("#moveMeIntoMain").prependTo($("#main"));
});
#main {
border: 2px solid blue;
min-height: 100px;
}
.moveMeIntoMain {
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main">main</div>
<div id="moveMeIntoMain" class="moveMeIntoMain">move me to main</div>
<button id="appendTo">appendTo main</button>
<button id="prependTo">prependTo main</button>
My solution:
Move:
jQuery("#NodesToMove").detach().appendTo('#DestinationContainerNode')
copy:
jQuery("#NodesToMove").appendTo('#DestinationContainerNode')
Note the usage of .detach(). When copying, be careful that you are not duplicating IDs.
Use a vanilla JavaScript solution:
// Declare a fragment:
var fragment = document.createDocumentFragment();
// Append desired element to the fragment:
fragment.appendChild(document.getElementById('source'));
// Append fragment to desired element:
document.getElementById('destination').appendChild(fragment);
Check it out.
Try plain JavaScript: destination.appendChild(source);.
onclick = function(){ destination.appendChild(source) };
div {
margin: .1em;
}
#destination {
border: solid 1px red;
}
#source {
border: solid 1px gray;
}
<div id=destination>
###
</div>
<div id=source>
***
</div>
I just used:
$('#source').prependTo('#destination');
Which I grabbed from here.
If the div where you want to put your element has content inside, and you want the element to show after the main content:
$("#destination").append($("#source"));
If the div where you want to put your element has content inside, and you want to show the element before the main content:
$("#destination").prepend($("#source"));
If the div where you want to put your element is empty, or you want to replace it entirely:
$("#element").html('<div id="source">...</div>');
If you want to duplicate an element before any of the above:
$("#destination").append($("#source").clone());
// etc.
You can use:
To insert after,
jQuery("#source").insertAfter("#destination");
To insert inside another element,
jQuery("#source").appendTo("#destination");
You can use the following code to move the source to the destination:
jQuery("#source")
.detach()
.appendTo('#destination');
Try the working CodePen.
function move() {
jQuery("#source")
.detach()
.appendTo('#destination');
}
#source{
background-color: red;
color: #ffffff;
display: inline-block;
padding: 35px;
}
#destination{
background-color:blue;
color: #ffffff;
display: inline-block;
padding: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="source">
I am source
</div>
<div id="destination">
I am destination
</div>
<button onclick="move();">Move</button>
If you want a quick demo and more details about how you move elements, try this link:
http://html-tuts.com/move-div-in-another-div-with-jquery
Here is a short example:
To move ABOVE an element:
$('.whatToMove').insertBefore('.whereToMove');
To move AFTER an element:
$('.whatToMove').insertAfter('.whereToMove');
To move inside an element, ABOVE ALL elements inside that container:
$('.whatToMove').prependTo('.whereToMove');
To move inside an element, AFTER ALL elements inside that container:
$('.whatToMove').appendTo('.whereToMove');
I need to move content from one container to another including all the event listeners. jQuery doesn't have a way to do it, but the standard DOM function appendChild does.
// Assuming only one .source and one .target
$('.source').on('click',function(){console.log('I am clicked');});
$('.target')[0].appendChild($('.source')[0]);
Using appendChild removes the .source* and places it into target including its event listeners: Node.appendChild() (MDN)
You may also try:
$("#destination").html($("#source"))
But this will completely overwrite anything you have in #destination.
You can use pure JavaScript, using appendChild() method...
The appendChild() method appends a node as the last child of a node.
Tip: If you want to create a new paragraph, with text, remember to
create the text as a Text node which you append to the paragraph, then
append the paragraph to the document.
You can also use this method to move an element from one element to
another.
Tip: Use the insertBefore() method to insert a new child node before a
specified, existing, child node.
So you can do that to do the job, this is what I created for you, using appendChild(), run and see how it works for your case:
function appendIt() {
var source = document.getElementById("source");
document.getElementById("destination").appendChild(source);
}
#source {
color: white;
background: green;
padding: 4px 8px;
}
#destination {
color: white;
background: red;
padding: 4px 8px;
}
button {
margin-top: 20px;
}
<div id="source">
<p>Source</p>
</div>
<div id="destination">
<p>Destination</p>
</div>
<button onclick="appendIt()">Move Element</button>
I noticed huge memory leak & performance difference between insertAfter & after or insertBefore & before .. If you have tons of DOM elements, or you need to use after() or before() inside a MouseMove event, the browser memory will probably increase and next operations will run really slow.
The solution I've just experienced is to use inserBefore instead before() and insertAfter instead after().
Dirty size improvement of Bekim Bacaj's answer:
div { border: 1px solid ; margin: 5px }
<div id="source" onclick="destination.appendChild(this)">click me</div>
<div id="destination" >...</div>
For the sake of completeness, there is another approach wrap() or wrapAll() mentioned in this article. So the OP's question could possibly be solved by this (that is, assuming the <div id="destination" /> does not yet exist, the following approach will create such a wrapper from scratch - the OP was not clear about whether the wrapper already exists or not):
$("#source").wrap('<div id="destination" />')
// or
$(".source").wrapAll('<div id="destination" />')
It sounds promising. However, when I was trying to do $("[id^=row]").wrapAll("<fieldset></fieldset>") on multiple nested structure like this:
<div id="row1">
<label>Name</label>
<input ...>
</div>
It correctly wraps those <div>...</div> and <input>...</input> BUT SOMEHOW LEAVES OUT the <label>...</label>. So I ended up use the explicit $("row1").append("#a_predefined_fieldset") instead. So, YMMV.
The .appendChild does precisely that - basically a cut& paste.
It moves the selected element and all of its child nodes.

Categories

Resources