How to bind to 'inview' event on multiple elements - javascript

I'm playing around with Velocity.js and jquery.inview, and I want all the titles on my page to slideDownIn when they come into view. This code works fine for the first title:
$('.movies-title').bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
if (isInView) {
// element is now visible in the viewport
if (visiblePartY == 'top') {
// top part of element is visible
} else if (visiblePartY == 'bottom') {
// bottom part of element is visible
} else {
// whole part of element is visible
$(this).velocity("transition.slideDownIn", 500);
}
} else {
// element has gone out of viewport
$(this).velocity("reverse");
}
});
If I copy and paste the above several times and replace .movies-title with the classes of the other titles, it works as I want it to.
However, that seems like a lot of extra code. I tried changing $('.movies-title') to $(.movies-title, .tv-title, .books-title) but then the animation only works for the last element in the list. I also tried adding a new class called .title to all of the titles and changing .movie-title to .title but that didn't work either.
What am I doing wrong? How can I condense the code?

The best solution is to use a single class on each of these elements since they have something so in common. You might just add title as a class type and apply it to that class.
<div class="title movie-title"></div>
I know you mentioned this in your question, but I can't see why this wouldn't work.

Try using delegate instead of bind for multiples. Also make a unified class for all of them (I just used title)
so like this -
$('body').delegate('.title','inview', function(event, isInView, visiblePartX, visiblePartY) {
Edit - sorry linked wrong fiddle initially
see fiddle http://jsfiddle.net/d1g7sLxq/3/

Related

jQuery: inserting text into container div on hover

I'm using a simple jQuery image slider (Owl Carousel) to show a list of speakers at a convention with photos, and I'm trying to find a way to overlay text associated with each speaker onto a div placed above the slider. I have a mockup page here. As you can see on the mockup, I have two primary divs-- i.e. div#sit and div#carousel-sit; within the former I have an container with the class .sit-quote-container into which I'd like the quote text/markup injected. I would like this overlay text to pull from the paragraph elements with the .sit-quote class that exist for each speaker.
In addition to the problem of displaying the appropriate text within the container div, I'm seeing that placing the .sit-quote paragraph within each slide is causing a gap to appear under the speaker name (the grey box underneath) and I have no idea why this is happening given that I've set .sit-quote to display:none. I'm wondering if perhaps I need to move the elements containing the quotations out of the slider markup altogether (?)
As for the actual hover function, this is what I have so far, with the help of another SO user; but it doesn't seem to be working:
$(".slide-sit").hover(function() {
var clone = $(this).find(".sit-quote").clone();
clone.appendTo(".sit-quote-container");
}, function(){
$(".sit-quote-container").html(""); // this clears the content on mouseout
});
Ultimately, I'd like the quotes to fade in/out positioned within the main div. Thanks for any assistance, and please let me know if I need to provide further clarification as to the aim here.
you should first visible that quote
try this:
$(".slide-sit").hover(function() {
var clone = $(this).find(".sit-quote").clone();
clone.appendTo(".sit-quote-container").show(); // Here you should show the quote
}, function(){
$(".sit-quote-container").html("");
});
if you want to fade in:
$(".slide-sit").hover(function() {
var clone = $(this).find(".sit-quote").clone();
clone.appendTo(".sit-quote-container").fadeIn(); //Here if you want to fade the quote
}, function(){
$(".sit-quote-container").html("");
});
Use the below script to pull the text from .sit-quote p tag of the hovered item and display it in the .sit-quote-container
UPDATE
If needed wrap the quote in a para tag and to avoid complexity use a different class name, in this case .sit-quote_inner.
CSS : .sit-quote_inner{ display:none; }
JS
$('.sit-carousel-container .owl-item').hover(function(){
var quote = $(this).find('.sit-quote').text(); //Only text not the p tag
quote = '<p class="sit-quote_inner">' + quote + '</p>';
$('.sit-header .sit-quote-container').html(quote);
$('.sit-quote_inner').fadeIn(); //Add this
},function(){
$('.sit-header .sit-quote-container').html('');
});
The carousel seems to be dynamically injecting clones of the slides. In this case, you might want to delegate your event handler so that it works with the dynamically generated slides.
Also, if you want to fadeOut the text, you should remove it in the complete callback of fafeOut instead of simply emptying the html Try
$(document).on("mouseenter",".slide-sit",function() {
var clone = $(this).find(".sit-quote").clone();
clone.appendTo(".sit-quote-container").fadeIn("slow");
});
$(document).on("mouseleave",".slide-sit", function(){
$(".sit-quote-container")
.find(".sit-quote")
.fadeOut("slow",function(){ // Fadeout and then remove the text
$(this).remove();
})
});
The gap (grey background) is the background of .slide-sit, which is visible due to the margin-bottom: 15px; applied on the paragraph containing name (style rule .item p main.css line 67 it seems), removing this will fix the issue.
Update
It'd be better if you keep a .slide-sit inside the .sit-quote-container so that you can fade it in/out properly using the below script.
$(document).on("mouseenter",".sit-carousel-container .slide-sit",function() {
var content = $(this).find(".sit-quote").html();
(".sit-quote-container .sit-quote").html(content).fadeIn("slow");
});
$(document).on("mouseleave",".sit-carousel-container .slide-sit", function(){
$(".sit-quote-container").find(".sit-quote").fadeOut("slow")
});

fadeIn() / fadeOut() animation not playing

Below I have this piece of code which I use to filter products with using a drop-down menu. The content of the #child_cat division changes based on the value attribute of the anchor tag:
$('#brandsort').change(function(){
$('#child_cat a').fadeOut(500);
$('[value="' + $(this).val() + '"]').fadeIn();
if ($('#brandsort option:selected').text() === "") {
$('#child_cat a').fadeIn(500);
}
});
The code will filter out the products that do not match their option value, but it won't play the animation. Right now, it acts more like a delayed .show() / .hide() function than anything. Please enlighten me from any wrongdoing in my code or what I could possibly be doing wrong aside from that.
EDIT:
I know the people on SO would normally like some hands-on help from one of you, but in this case I was specifically only asking for "enlightenment". Just some verbal input of what I could have been doing wrong.
To fulfill your request of providing some HTML, you'll find it here: http://jsfiddle.net/HJPN8/3/
There was a few mistakes in the logic that made this not work. Firstly, the reason you couldn't see the fade animate happen is because fade uses the css property opacity. Opacity only works on block and inline-block elements, and you were using the .fadeOut() on a tags which are display:inline. So that can be fixed easily with this:
#child_cat a{
display:block;
}
Next you're using .fadeOut() and .fadeIn() which both run at the same time meaning that the animations would both collide and not work properly. So you need to use callback functions to correctly time them. Below is the code I have refactored, I've included a lot of comments so you can see how it all works. The fade functions have been replaced with .animate() which is a lower end function that gives you more control which we need in this situation.
One last thing is that you were using the value attribute on your products, this isn't recommended as this property is specific to the options tag. If you wish to create custom attributes then the standard way is to prepend them with "data-" which you can see I've done here: http://jsfiddle.net/HJPN8/6/
$(function(){
var brandsort = $('#brandsort');
var products = $('#child_cat a');
brandsort.on('change', function(e){
var val = brandsort.val();
// If search is blank then select all products to show else filter specific products.
var filteredProducts = (val == '') ? products : products.filter('[data-value="' + val + '"]');
// Hide products and set callback for when the animation has finished.
// If we don't use a callback, the products will animate out and in at the same time, ruining the effect.
products.animate({opacity: 0}, 300).promise().done(function(){
// Now that he products' opacity is 0, we set them to display block to remove them from the flow of the DOM.
products.css({display: 'none'});
// Now Bring the filtered products back and animate them in again.
filteredProducts.css({display: 'block'}).animate({opacity: 1}, 500);
});
});
});

How to target text between two elements

Update Below
I'm trying to target the output of codemirror and add some custom events and styling to module elements.
Codemirror displays the following code as such.
<div><module type="content"></module><span>can contain other data</span></div>
In the DOM it is rendered between a series of spans.
<pre>
<span class="cm-tag"><div><module</span>
<span class="cm-attribute">type</span>
=
<span class="cm-string">"content"</span>
<span class="cm-tag">></module><span></span>
can contain other data
<span class="cm-tag"></span></div></span>
</pre>
The issue I'm having is trying to add a yellow background to the whole module element, but because the "=" part is between two elements, I'm not sure how to target it with a selector.
This is what I have right now, but because it does not include the text between the elements, there are gaps in the background color.
$('.cm-tag:contains("<module")').each(function () {
var $closingElement;
$(this).nextAll().each(function () {
if ($(this).text() == "></module>") {
$closingElement = $(this).next();
return false;
}
});
var $module =$(this).add($(this).nextUntil($closingElement));
$module.addClass('module');
});
Anyone have suggestion/ideas about how to accomplish this?
Update
I was able to get part way there by using the wrapAll jquery method, but the visible result still isn't quite right. Now the spaces and equal characters are removed from the wrapped element and placed after it.
<modulename"content"id"1234"/> = =
function hilightModules() {
$('.cm-tag:contains("<module")').each(function() {
var $module = $(this);
$(this).nextAll().each(function() {
$module = $module.add($(this));
// closing element
if ($(this).hasClass('cm-tag')) {
return false;
}
});
$module.wrapAll('<span class="module" />').click(function() {
// Do stuff
});
});
};
For adding click handlers to content text, your best bet is to just register a mousedown handler on the CodeMirror wrapper element, and, in that handler, determine whether the thing clicked is what you are looking for. Content elements may change at any time, and you don't want to register tons of handlers.
As for highlighting things, I'd recommend an overlay mode (see http://codemirror.net/demo/mustache.html for an example), rather than trying to do it with DOM munging (for the reasons listed above).
Like #Raminson said, you could target the <pre> tag to make the background span the entire section. Is this what you are looking for?
http://jsfiddle.net/ckaufman/CSzny/

not able to append html using jQuery (JavaScript)

In this jquery plugin:
http://www.stahs.org.uk/jquery.infinitecarousel.bak
There's this line:
$(obj).append('<div id="textholder'+randID+'" class="textholder" style="position:absolute;bottom:0px;margin-bottom:'+-imgHeight*o.textholderHeight+'px;left:'+$(obj).css('paddingLeft')+'"></div>');
Problem is when it dumps the text node in this div, it aligns to the top of the div. I want text to align to bottom of div. So I decided to create another div within this div:
$(obj).append('<div id="textholder'+randID+'" class="textholder" style="position:absolute;bottom:0px;margin-bottom:'+-imgHeight*o.textholderHeight+'px;left:'+$(obj).css('paddingLeft')+'"></div>');
console.log($('#textholder'+randID));
$('#textholder'+randID).append('<div style="display:table-cell; height: 94.25px; width: 1000px; vertical-align:bottom;"></div>');
The console outputs this:
[div#textholder35196647.textholder]
[div#textholder62315889.textholder]
[div#textholder95654959.textholder]
However, my above append is not working. The nested div never shows up, so when I later do this:
if(t != null)
{
$('#textholder'+randID+' div').html(t).animate({marginBottom:'0px'},500); // Raise textholder
showminmax();
}
No text becomes visible because the nested div never gets created.
So I am extremely confused. If you look at original plugin, this line works:
$('#textholder'+randID+' div').html(t)
How is it able to target the right div here yet when I append to it right after it's created, it doesn't exist, as you guys suggest?
This doesn't work either:
var $texthold = jQuery('<div id="textholder'+randID+'" class="textholder" style="position:absolute;bottom:0px;margin-bottom:'+-imgHeight*o.textholderHeight+'px;left:'+$(obj).css('paddingLeft')+'"></div>');
$(obj).append($texthold);
$texthold.append('<div></div>')
Thanks for response.
It sounds as though perhaps randID has been modified between the $(obj).append... line and your added $('#textholder'+randID)... line. Are you quite sure the value of randID is the same on the two lines?
Are you sure that $(obj) really refers to the element you want to append to? Just in case, you might want to try it the other way round:
$('<div id="textholder'+randID+'" class="textholder" style="position:absolute;'
+'bottom:0px;margin-bottom:'+(-imgHeight*o.textholderHeight)
+'px;left:'+$(obj).css('paddingLeft')+'"></div>'
).appendTo(obj);
It appears this worked:
function showtext(t)
{
if(t != null)
{
if(typeof $('#textholder'+randID).find('div')[0] == 'undefined'){
$('#textholder'+randID).append('<div style="display:table-cell; height: 94.25px; vertical-align:bottom;"></div>');
}
$('#textholder'+randID+' div').html(t);
$('#textholder'+randID).animate({marginBottom:'0px'},500); // Raise textholder
showminmax();
}
}
It's just kind of crazy I had to resort to using typeof to check whether div is declared or not. Why the author of the plugin decided to randomly assign integers as ids of divs is beyond me. By doing that, it appears javascript has difficulty retaining the randomly created id. That's my only explanation for the unusual behavior I could come up with.
Try:
$(obj).after('html');
Documentation is here.

Toggle effect problem when using for-loop in IE7

I'm a webdesigner that's trying to get the hang of JavaScript and jQuery, and I want to learn how to write shorter, more concise code - to avoid being ridiculed by the developers at work ;)
I have this snippet:
// toggle divs when checkbox is checked
$('.product-optional-checkbox1').click(function () {
$('.product-optional-toggle1').toggle('fast');
});
$('.product-optional-checkbox2').click(function () {
$('.product-optional-toggle2').toggle('fast');
});
$('.product-optional-checkbox3').click(function () {
$('.product-optional-toggle3').toggle('fast');
});
// hide divs
$('.product-optional-toggle1').hide();
$('.product-optional-toggle2').hide();
$('.product-optional-toggle3').hide();
...that I want to reduce using a for-loop, like this:
for( var i = 1; i < 4; ++i ) {
$('.product-optional-checkbox' + i).click(function () {
$(this).parent('div').find('div').toggle('fast');
});
$('.product-optional-toggle' + i).css({ display: 'none'});
};
It works fine in FF, however in IE7 it toggles twice. Anyone know who to solve a problem like this?
It's hard to say without seeing the HTML structure but maybe going to the parent then descendants is finding multiple divs?
In your example, you could replace:
$(this).parent('div').find('div').toggle('fast');
With code more similar to the original examples:
$('.product-optional-toggle' + i).toggle('fast');
However, it would be much better to ditch all the numbers and just use a class of .product-optional-checkbox. This way you can add a click function to all elements of that class in one go and avoid the loop:
$('.product-optional-checkbox').click(function () {
// do stuff using $(this)
});
Given that your click events seem to be tied to checkboxes (based on the class names you have in your example), why not actually provide code to handle click events for those checkboxes? For example:
<div id='my_group_of_checkboxes'>
<input type="checkbox" id="checkbox1">
<input type="checkbox" id="checkbox2">
...
</div>
And your jQuery code is then stripped down to three lines:
$('#my_group_of_checkboxes :checkbox').click(function(){
$(this).parent('div').hide('fast');
});
You also seem to need to hide the <div> elements related to each checkbox:
$('div[class^="product-optional"]').hide();
Although ID selectors would be a better option here and, depending on their position within your page, you may even be able to get away with something like:
$('#my_container_div_id div').hide();
If you can post some of your HTML, that might help provide more accurate answers as well.

Categories

Resources