jQuery: var(s) set for three functions - javascript

After a long search I didn't find what I am looking for, or if I did, it didn't work for what I am doing or I didn't know how to use it properly. In all cases I really need your help in this matter.
What I did is defining my processing div by only identifying the div(s) with ID
then the rest is written in jQuery. There is a lot of code, so I'll put up a shortened version.
HTML
<div id="blue" class='processing'>
<div class="bar"></div>
<div class="text">BLUE</div>
</div>
<div id="red" class='processing'>
<div class="bar"></div>
<div class="text">RED</div>
</div>
<div id="yellow" class='processing'>
<div class="bar"></div>
<div class="text">YELLOW</div>
</div>
jQuery
$(".processing").click(function () {
var $this = $(this);
var ID = $this.attr('id');
switch(ID){
case "blue":
var name = $this.find(".text").text();
var width = 60;
// some other var(s)
break;
case "red":
var name = $this.find(".text").text();
var width = 40;
// some other var(s)
break;
case "yellow":
var name = $this.find(".text").text();
var width = 20;
// some other var(s)
break;
}
$this.find(".text").text("THE " + name);
$this.find(".bar").css("width", width + "%");
// some other complicated coding
});
Explanation of what the code does
This is the simple version, the html for all div(s) is the same but the IDs are different and the text div also. Once the div is clicked, the code will get the ID then match it with the switch to get the right variables for it, (there are a lot more variables than this). Let's say that the div marked with the ID blue is clicked, the div marked with class bar inside blue, its width will change to 60% according to the switch. If red was clicked, the bar's width for red will change to 40% and so on.
All the important variables are inside the click function. what I want is...
What I want
Before clicking, I want the user to be able to hover the mouse over the bar and next to the text the parentage will show up without clicking, then disappear once the mouse is away.
I know how to do that with functions, using mouseenter, and mouseleave.
The problem
the problem is... I'll have to use the variables 3 times. For mouseenter, mouseleave and for click. How could I do that or what should I do with the variables so I will be able to use them inside these three functions without repeating them.
The processing div is a rectangle,
the bar div is the background,
and the text div is the text over the processing bar.
Picture to explain: http://i.imgur.com/nFSrvy6.png
1 Reminder
In this example the var I want to use in all functions is width. But in the code I have (long version), not just one variable.

Why don't you declare all your variables inside an object:
var data = {
blue: {
width: 60,
// other variables
},
red: {
width: 40,
// other variables
},
yellow: {
width: 20,
// other variables
}
}
Then you can use your data object wherever you need it:
var ID = $this.attr('id');
var width = data[ID].width;

Robby's answer is good. I'm also a big fan of the data attribute for embedding element-specific stuff right into the element.
I'm also using the data attribute to mark the element as clicked when it's been clicked, so that mouseover and mouseleave can look for that and have different behaviors when it's already clicked (if any at all).
<div id="blue" class="processing" data-width="60">
<div class="bar"></div>
<div class="text">BLUE</div>
</div>
<div id="red" class="processing" data-width="40">
<div class="bar"></div>
<div class="text">RED</div>
</div>
<div id="yellow" class="processing" data-width="20">
<div class="bar"></div>
<div class="text">YELLOW</div>
</div>
$(".processing").on("mouseover", function () {
if( ! $(this).data("clicked")){
//if it hasn't been clicked yet, do something
}else{
//otherwise, leave it alone
}
});
$(".processing").on("mouseleave", function () {
if( ! $(this).data("clicked")){
//if it's already clicked, leave it alone
}else{
//otherwise, revert the changes from mouseover
}
});
$(".processing").on("click", function () {
var name = $(this).find(".text").text();
var width = $(this).data("width");
$(this).find(".text").text("THE " + name);
$(this).find(".bar").css("width", width + "%");
$(this).data("clicked", true); //mark the div as clicked
// some other complicated coding
});

Related

dynamically insert div after row containing floating divs jquery [duplicate]

I have a number of divs floating in several rows. The divs contain text-previews and a link to slide down the full content (see http://jsfiddle.net/yDcKu/ for an example).
What happens now: When you slide down the content-div it opens right after the connected preview.
What I want to happen: Open the content-div after the last div in the row.
I assume the could be done by:
1. find out which div is the last one in the row of the activated preview,
2. add an id to this div and
3. append the content-div to this div.
I have a solution for steps 2 und 3 using jQuery but no guess how to do the first step.
I can manage to get the document width and the x- and y-value of each div but I have no idea how to find out which div has the highest x- as well the highest y-value and as well is in the row of the activated preview-div.
Any idea anyone? Thanks
Here is an example that does what you want. I simplified your code, so you don't have to manually ID every entry and preview.
http://jsfiddle.net/jqmPc/1/
It's a little complicated. Let me know if you have questions.
Basically, when the window is resized, the script goes through and finds the first preview in each row by finding the preview with the same left offset as the very first one. It then adds a class last to the entry before (previous row) and class first to this preview. I do css clear: left on both of these so that everything wraps normally when the entries open.
I made your code generic, without IDs:
<div class="preview">
<p>Some preview text <a class="trigger" href="#">…</a></p>
</div>
<div class="entry">
<div class="close_button">
<a class="close" href="#">×</a>
</div>
<p>Some content text.</p>
</div>
This makes you not have to write the same code over and over.
The open/close script:
$('.trigger').click(function() {
$('.openEntry').slideUp(800); // Close the open entry
var preview = $(this).closest('.preview'); // Grab the parent of the link
// Now, clone the entry and stick it after the "last" item on this row:
preview.next('.entry').clone().addClass('openEntry').insertAfter(preview.nextAll('.last:first')).slideDown(800);
});
// Use "on()" here, because the "openEntry" is dynamically added
// (and it's good practice anyway)
$('body').on('click', '.close', function() {
// Close and remove the cloned entry
$('.openEntry').slideUp(800).remove();
});
This could be simplified a bit I'm sure, especially if you were willing to reformat your html a little more, by putting the entry inside of the preview element (but still hidden). Here is a slightly simpler version, with the html rearranged:
http://jsfiddle.net/jqmPc/2/
(I also color the first and last element on the line so you can see what is going on)
You could just get the last div in the array after calling getElementsByTagName.
var divArray = wrapperDiv.getElementsByTagName("div");
if(divArray.length > 0)
var lastDiv = divArray[divArray.length-1];
else
console.log("Empty!");
i am not able to correctly understand your question, but if you want to find out last div element in the document then you can do something like this
$("div:last")
so this will give you last div of the document
Reference:
http://api.jquery.com/last-selector/
$([1,2]).each(function(idx,el) {
$("#entry" + el).hide().insertAfter("div.entry:last");
$("#trigger" + el).click(function() {
$("#entry" + el).slideDown('800');
});
$("#close" + el).click(function() {
$("#entry" + el).slideUp('800');
});
});​
http://jsfiddle.net/yDcKu/11/
I got same problem as yours, and I have been redirected to this question. But I think the answer is too complicated to my need. So I made my own way. Supposedly, you get your div list from a JSON, you can do this:
product[0] = {id: "name1", text: "text1"}
product[1] = {id: "name2", text: "text2"}
product[2] = {id: "name3", text: "text3"}
private getLastElement(id, products) {
const getTop = (id) => $("#" + id).position().top;
let itemPos = getTop(id);
let itemIndex = products.map(x => x.id).indexOf(id);
let lastID = itemIndex;
while (lastID < products.length - 1) {
if (getTop(products[lastID + 1].id) > itemPos) break;
lastID++;
}
return products[lastID].id;
}
But you can also find out by gathering all id inside your wrapper.
It works by scanning next id's row position, and return the last id of the same row.
I was looking for the same but on a single element to add style on first and last elements. #Jeff B answer helped me so alter and use it for me on one element. So the search phrase 'Get the last div in a row of floating divs' and someone looking for the same, this code may helpful:
Fiddle: https://jsfiddle.net/kunjsharma/qze8n97x/2/
JS:
$(function() {
$(window).on('resize', function() {
var startPosX = $('.preview:first').position().left;
$('.preview').removeClass("first last");
$('.preview').each(function() {
if ($(this).position().left == startPosX) {
$(this).addClass("first");
$(this).prevAll('.preview:first').addClass("last");
}
});
$('.preview:last').addClass("last");
});
$(window).trigger('resize');
});
CSS:
.preview {
float: left;
}
HTML:
<div class="preview">
<p>Some preview text</p>
</div>
<div class="preview">
<p>Some preview text</p>
</div>
<div class="preview">
<p>Some preview text</p>
</div>
<div class="preview">
<p>Some preview text</p>
</div>

javascript replace div on each click

The following works to replace a div with a new div...
<div id = "div1" style="display:block" onclick = "replace()"><img src="1.jpg" /></div>
<div id = "div2" style="display:none"><img src="2.jpg" /></div>
<script type = "text/javascript">
function replace() {
document.getElementById("div1").style.display="none";
document.getElementById("div2").style.display="block";
}
</script>
What I can't figure out is how to make this work so when you click div2 it is replaced by div3 and so on.
In other words, I want to replace the div on each click more than just once. What's the best way to go about this? I'm a novice, so not sure if the above is a good start or not.
Thanks!
You could make a more generic function:
function replace( hide, show ) {
document.getElementById(hide).style.display="none";
document.getElementById(show).style.display="block";
}
Then you can create many divs and use the same function:
<div id = "div1" style="display:block" onclick = "replace('div1','div2')">...</div>
<div id = "div2" style="display:none" onclick = "replace('div2','div3')">..</div>
<div id = "div3" style="display:none" onclick = "replace('div3','div4')">..</div>
...
I will suggest you some best practices in this answer:
Use classes instead of the style property, it's way nicer for the browser.
Don't use inline event handler. See the example below.
It's not "replace" you're looking for, it's "toggling".
I suggest you use event bubbling. This way, you add a single event on the container of all your div, and you can work on this.
Alright, now for the example:
HTML:
<div id="container">
<div id="div1">..</div>
<div id="div2" class="hidden">..</div>
<div id="div3" class="hidden">..</div>
</div>
JS:
// Notice how I declare an onclick event in the javascript code
document.getElementById( 'container' ).onclick = function( e ) {
// First, get the clicked element
// We have to add these lines because IE is bad.
// If you don't work with legacy browsers, the following is enough:
// var target = e.target;
var evt = e || window.event,
target = evt.target || evt.srcElement;
// Then, check if the target is what we want clicked
// For example, we don't want to bother about inner tags
// of the "div1, div2" etc.
if ( target.id.substr( 0, 3 ) === 'div' ) {
// Hide the clicked element
target.className = 'hidden';
// Now you have two ways to do what you want:
// - Either you don't care about browser compatibility and you use
// nextElementSibling to show the next element
// - Or you care, so to work around this, you can "guess" the next
// element's id, since it remains consistent
// Here are the two ways:
// First way
target.nextElementSibling.className = '';
// Second way
// Strip off the number of the id (starting at index 3)
var nextElementId = 'div' + target.id.substr( 3 );
document.getElementById( nextElementId ).className = '';
}
};
And of course, the CSS:
.hidden {
display: none;
}
I highly suggest you read the comments in the javascript code.
If you read carefully, you'll see that in modern browsers, the JS code is a matter of 5 lines. No more. To support legacy browsers, it requires 7 lines.

Get the last div in a row of floating divs

I have a number of divs floating in several rows. The divs contain text-previews and a link to slide down the full content (see http://jsfiddle.net/yDcKu/ for an example).
What happens now: When you slide down the content-div it opens right after the connected preview.
What I want to happen: Open the content-div after the last div in the row.
I assume the could be done by:
1. find out which div is the last one in the row of the activated preview,
2. add an id to this div and
3. append the content-div to this div.
I have a solution for steps 2 und 3 using jQuery but no guess how to do the first step.
I can manage to get the document width and the x- and y-value of each div but I have no idea how to find out which div has the highest x- as well the highest y-value and as well is in the row of the activated preview-div.
Any idea anyone? Thanks
Here is an example that does what you want. I simplified your code, so you don't have to manually ID every entry and preview.
http://jsfiddle.net/jqmPc/1/
It's a little complicated. Let me know if you have questions.
Basically, when the window is resized, the script goes through and finds the first preview in each row by finding the preview with the same left offset as the very first one. It then adds a class last to the entry before (previous row) and class first to this preview. I do css clear: left on both of these so that everything wraps normally when the entries open.
I made your code generic, without IDs:
<div class="preview">
<p>Some preview text <a class="trigger" href="#">…</a></p>
</div>
<div class="entry">
<div class="close_button">
<a class="close" href="#">×</a>
</div>
<p>Some content text.</p>
</div>
This makes you not have to write the same code over and over.
The open/close script:
$('.trigger').click(function() {
$('.openEntry').slideUp(800); // Close the open entry
var preview = $(this).closest('.preview'); // Grab the parent of the link
// Now, clone the entry and stick it after the "last" item on this row:
preview.next('.entry').clone().addClass('openEntry').insertAfter(preview.nextAll('.last:first')).slideDown(800);
});
// Use "on()" here, because the "openEntry" is dynamically added
// (and it's good practice anyway)
$('body').on('click', '.close', function() {
// Close and remove the cloned entry
$('.openEntry').slideUp(800).remove();
});
This could be simplified a bit I'm sure, especially if you were willing to reformat your html a little more, by putting the entry inside of the preview element (but still hidden). Here is a slightly simpler version, with the html rearranged:
http://jsfiddle.net/jqmPc/2/
(I also color the first and last element on the line so you can see what is going on)
You could just get the last div in the array after calling getElementsByTagName.
var divArray = wrapperDiv.getElementsByTagName("div");
if(divArray.length > 0)
var lastDiv = divArray[divArray.length-1];
else
console.log("Empty!");
i am not able to correctly understand your question, but if you want to find out last div element in the document then you can do something like this
$("div:last")
so this will give you last div of the document
Reference:
http://api.jquery.com/last-selector/
$([1,2]).each(function(idx,el) {
$("#entry" + el).hide().insertAfter("div.entry:last");
$("#trigger" + el).click(function() {
$("#entry" + el).slideDown('800');
});
$("#close" + el).click(function() {
$("#entry" + el).slideUp('800');
});
});​
http://jsfiddle.net/yDcKu/11/
I got same problem as yours, and I have been redirected to this question. But I think the answer is too complicated to my need. So I made my own way. Supposedly, you get your div list from a JSON, you can do this:
product[0] = {id: "name1", text: "text1"}
product[1] = {id: "name2", text: "text2"}
product[2] = {id: "name3", text: "text3"}
private getLastElement(id, products) {
const getTop = (id) => $("#" + id).position().top;
let itemPos = getTop(id);
let itemIndex = products.map(x => x.id).indexOf(id);
let lastID = itemIndex;
while (lastID < products.length - 1) {
if (getTop(products[lastID + 1].id) > itemPos) break;
lastID++;
}
return products[lastID].id;
}
But you can also find out by gathering all id inside your wrapper.
It works by scanning next id's row position, and return the last id of the same row.
I was looking for the same but on a single element to add style on first and last elements. #Jeff B answer helped me so alter and use it for me on one element. So the search phrase 'Get the last div in a row of floating divs' and someone looking for the same, this code may helpful:
Fiddle: https://jsfiddle.net/kunjsharma/qze8n97x/2/
JS:
$(function() {
$(window).on('resize', function() {
var startPosX = $('.preview:first').position().left;
$('.preview').removeClass("first last");
$('.preview').each(function() {
if ($(this).position().left == startPosX) {
$(this).addClass("first");
$(this).prevAll('.preview:first').addClass("last");
}
});
$('.preview:last').addClass("last");
});
$(window).trigger('resize');
});
CSS:
.preview {
float: left;
}
HTML:
<div class="preview">
<p>Some preview text</p>
</div>
<div class="preview">
<p>Some preview text</p>
</div>
<div class="preview">
<p>Some preview text</p>
</div>
<div class="preview">
<p>Some preview text</p>
</div>

jQuery: How to assign the right ID to a button dynamically

I have a JS/jQuery script that adds our leads (web contacts) to the DOM in a for loop. Everything works fine except for one thing. I want the body of the lead to be hidden upon the initial display, and then have a slideToggle button to display or hide the details That means dynamically adding click events to each button as it is created. The entire HTML (HTML and a JSON object mixed into the HTML) of the lead and the slideToggle button are all appended to a node in the DOM in the for loop. Here is the pertinent part of the for loop:
// Hide the body of the lead; just show the title bar and the first line
var dataID = data[i].id
var div = $('#row' + dataID);
var more = $('#more' + dataID);
div.hide();
// Create click event for each "+" button
more.click(function() {
div.slideToggle();
});
But when I click on the "+" button to reveal the details, it opens the last div, not the div I am trying to open. This is true no matter how many leads I have on the page. How do I get the click event to open the right div. If I console.log "div" in the click event, it gives me the ID of the last div, not the one I am clicking on. But if I console.log(div) outside the click event, it has the right ID.
Also, I was unsure whether I needed the "vars" in the loop or if I should declare them outside the loop.
Here is the HTML. It's one lead plus the beginning of the next lead, which I left closed in Firebug
<div id="lead1115">
<div id="learnmore">
<a id="more1115" class="more" href="#">+</a>
</div>
<div id="lead-info">
<div id="leadID">Lead ID# Date: March 27, 2012 11:26 AM (Arizona time)</div>
<div id="company">No company given</div>
<div id="name">Meaghan Dee</div>
<div id="email">
meaghan.dee#gmail.com
</div>
<br class="clearall">
<div>
<div id="row1115" style="display: none;">
<div id="phone">No phone given</div>
<div id="source">www.ulsinc.com/misc/expert-contact/</div>
<div id="cp-name">No channel partner chosen</div>
<br class="clearall">
<div id="location">
No location given
<br>
<strong>IP Address:</strong>
198.82.10.87
<br>
<span>Approximate Location: Blacksburg, Virginia, United States</span>
<br>
</div>
<div id="details">
<strong>Questions/Comments</strong>
<br>
We have the Professional Series Universal Laser Systems (laser cutter), and I wondered how I would order a high power density 2.0 replacement lens.nnThank you
</div>
</div>
</div>
</div>
<div id="learnmore">
<a id="1115|send_message" class="verify" href="#">Verify</a>
<a id="1115|send_message" class="markAsSpam" href="#">Spam</a>
<a id="1115|send_message" class="markAsDuplicate" href="#">Duplicate</a>
</div>
</div>
<br class="clearall">
<div id="lead1116">
<br class="clearall">
Try using .bind (or .on for 1.7+) and the data parameter.
more.bind("click",{target:div},function(e){
e.data.target.show();
}
or
more.on("click",{target:div},function(e){
e.data.target.show();
}
I think your basic problem is that div is common as a variable to all items. You have to separate the div's from each other by, for example, creating a local function and call it for each item. Something like:
function buildMore(div) {
more.click(function() {
div.slideToggle();
});
}
and in the loop call:
addMore(div);
p.s.
Whether you declare your variables inside or outside the loop doesn't matter: you still get the same variables.
This is because div variable gets changed and settles with the last value set in the loop.
Try this:
...
funciton createClick(div) {
return function() { div.slidToggle();
}
more.click( createClick(div) );
...
The variable div doesn't stay frozen with your click handler so it's value will be what it was at the end of the for loop and all click handlers will use the same value (which is what you're seeing).
There are a number of different ways to approach this and I thought all would be educational. Any one of them should work.
Idea #1 - Manufacture the row id from the clicked on more id
Use the id value on the clicked on link to manufacture the matching row ID. Since you create them in pairs, this can be done programmatically like this:
// Hide the body of the lead; just show the title bar and the first line
var dataID = data[i].id
$('#row' + dataID).hide();
$('#more' + dataID).click(function() {
// manufacture the row ID value from the clicked on id
var id = this.id.replace("more", "#row");
$(id).slideToggle();
});
Idea #2 - Use a function closure to "freeze" the values you want
Another way to do that is to create a function and closure that will capture the current value of div:
// Hide the body of the lead; just show the title bar and the first line
var dataID = data[i].id
var div = $('#row' + dataID).hide();
var more = $('#more' + dataID);
function addClick(moreItem, divItem) {
// Create click event for each "+" button
moreItem.click(function() {
divItem.slideToggle();
});
}
addClick(more, div);
Idea #3 - Use the HTML spatial relationship to find the row associated with a more
To make this work, you need to put a common class=lead on the top level lead div like this:
<div id="lead1115" class="lead">
And, a common class on each row:
<div id="row1115" class="row" style="display: none;">
Then, you can use the position relationships to find the row object that is in the same parent lead object as the clicked on more link like this:
// Hide the body of the lead; just show the title bar and the first line
var dataID = data[i].id
$('#row' + dataID).hide();
$('#more' + dataID).click(function() {
// find out common parent, then find the row in that common parent
$(this).closest(".lead").find(".row").slideToggle();
});
Idea #4 - Put the row ID as data on the more link
// Hide the body of the lead; just show the title bar and the first line
var dataID = data[i].id
$('#row' + dataID).hide();
$('#more' + dataID).data("row", "#row" + dataID).click(function() {
// get the corresponding row from the data on the clicked link
var rowID = $(this).data("row");
$(rowID).slideToggle();
});

Drag and drop with 2 drop target

I am looking for an example of drag and drop where the drag item has two distinct areas that have to match up with two droppable areas.
Example:
I would like the blue drag item to revert unless it is dropped in a position where each of its red children land on a green area.
Ideally I would like to use jquery ui (as I have experience with it), but any javascript library would be fine, thanks in advance.
You can accomplish this by using a combination of draggable/droppable options. Given HTML like this:
<div id="blue" class="valid">
<div id="red-one" class="red"></div>
<div id="red-two" class="red"></div>
</div>
<div id="green-container">
<div id="green-one" class="green">
</div>
<div id="green-two" class="green">
</div>
</div>
(omitting CSS, I did add some rules, see in the fiddle below).
You can write JavaScript like this:
function isInside(one, other) {
return one.offset().left >= other.offset().left &&
one.offset().top >= other.offset().top &&
one.offset().top + one.height() <= other.offset().top + other.height() &&
one.offset().left + one.width() <= other.offset().left + other.width();
}
$("#blue").draggable({
drag: function(event, ui) {
var $this = $(this);
var $reds = $this.children(".red");
var $greens = $("#green-container").children(".green");
var firstRed = $reds.first();
var firstGreen = $greens.first();
var secondRed = $reds.last();
var secondGreen = $greens.last();
if (isInside(firstRed, firstGreen) && isInside(secondRed, secondGreen)) {
$this.addClass('valid');
}
else {
$this.removeClass('valid');
}
},
revert: 'invalid'
});
$("#green-container").droppable({ accept: ".valid" });
Check it out here: http://jsfiddle.net/andrewwhitaker/g6FKz/
Notes:
For some reason I had to apply the 'valid' class initially to the 'blue' div, or else the target droppable would not accept the dragged element, even if it was valid (would appreciate some input on this). Not sure what's up with that, might be a bug in jQueryUI. Not a huge deal though.
The target droppable isn't exactly the two green elements, it's a white div that contains those elements. This should be clear from the example.
Every time you move the draggable div, the "drag" event is called, which determines if the red boxes are inside the green ones and assigns a valid class to the draggable div. The droppable object only accepts valid draggables.
Hope that helps!

Categories

Resources