Fire Ajax Rest call only for elements in viewport - javascript

i've got the following problem.
We're using a template which generates a list of divs, all with the same classes etc.
Each div contains a hidden input field containing the ID of the target site it links to.
Now my job is to use this ID to generate ajax rest calls for each of the divs to receive the amount of comments on the target site.
My current solution is a simple jQuery each, iterating through all divs and firing a rest call for each div containing the individual target ID and then appending the number of comments on the target page.
However, there might be a huge amount of divs on the page, so the customer only wants the rest calls of the currently viewable divs fired while scrolling down the page.
Is there any way to do this?
IMPORTANT INFORMATION: i have to use jQuery 1.7 and it has to work in IE8! -.-
kind regards
Additional info:
All divs that are rendered by the template are visible, so i can't check for :visible. I need a way to check if they are in the viewport. I tried some inview-plugins etc., but they need a specific ID they are tied to, and then check if the element with this ID comes into view. However, all my elements have the same class and no ID at all as they are rendered by the same template.

You can try with $('.element').is(":visible")
http://jsfiddle.net/4mu18z2y/1/
I haven't tested it in IE8 though.

You have to get the window position and the offset top of each element...
$(document).ready(function(){
var windowSize = $(window).height();
console.log("Window size: " + windowSize);
$(".test").each(function(){
var top = $(this).offset().top; // element top position
if(top < windowSize){
console.log($(this));
// your ajax call
}
});
});
Finddle: http://jsfiddle.net/m2wnbp2c/

Related

Why does changed value not display after breakpoint? Part 2

A value in tab header changed through JS value is not persisting on #media breakpoint/accordion screen - although the one in the tabbed content area is persisting.
The js code:
function check_1_input(X, Y) {
var ids=X.split("_"); console.log(' X '+X+' id '+ids[1]);
var PX=document.getElementById(X);
var PY=document.getElementById(Y);
PX.childNodes[0].textContent = "Changed";
PY.childNodes[0].textContent = "Changed";
}
which makes the changes is at the end of the html - not sure why it only works in that location.
The fiddle is
https://jsfiddle.net/PhilB/077dbf37/10/
The problem you're having is that you're using element IDs in your check_1_input function. The responsive tab plugin clones your tab elements on initialization to have both horizontal and vertical tabs with different classes that get hidden or exposed based on the media width, but it keeps the IDs the same. Since your function is looking for elements using getElementById, it will only find the first one.
Ultimately, you end up with two different elements with the same ID, which is bad practice. Using a class as the selector instead of the ID fixes the problem. I used jQuery to select the classes instead of ID's since you have jQuery loaded. You may consider removing the ID's all together in the tab elements, since the responsive tab plugin is always going to clone them and result in an invalid DOM (two elements with the same ID).
See my updated version of your fiddle here.

javascript get size of element with hidden parents

I need to determine the height of a DOM element using javascript - specifically, in my case, a div containing some text. Due to the way that HTML works, I can only reliably do this if the element is visible. The general purpose solution is to show the element, get it's height, and then hide it - simple enough in the single element case.
However, in the general case, the element in question may be a child of other elements that are hidden, thus preventing the above solution from working - calling jQuery's show() function on the element in question doesn't actually cause it to be shown due to the hidden parent, so you still can't get the height.
How can I make an element visible long enough to get its height, taking into account any parent elements that need to be made visible to make it work?
Use case: I'm trying to write some code that I can apply to any table element, that creates some other elements whose height should match the height of the table header. I want to keep the code generic enough that it will work regardless of where in the DOM the table is located, or if it is currently visible. An alternate solution would be to have some javascript that simply adjusts the size of the created elements when the size of the table header changes (such as when it is shown), but conceptually that seems less efficient. Still, if it is easier, I will accept that as an answer.
Edit: To give an example, while keeping in mind I am going for a general solution that is not tied to this specific HTML layout, consider the following HTML:
<div style="display:none; line-height:22px; font-size:18px;">
...Some random text or other content...
<div id="desired_size">
I want to find the height of this div when visible
</div>
...Possibly some more content/other stuff...
</div>
The goal is to get the height of that inner div, but I can't do that because it isn't displayed - it is hidden due to the parent div being hidden. If all I know about the HTML is the desired_size div, how would I go about making it visible enough to get the height? Granted, this example is trivial, but I'm trying to generalize it.
Edit 2: One suggestion was to clone the element and move it to somewhere that is visible. This works, but with a caveat: any inherited CSS properties that would affect the size are lost.
Edit 3: I'm trying to write a block of code that I can re-use in a variety of web pages, not just coding to a specific layout. As such, I can't make any assumptions about or changes to the parent HTML. The example above shows one case where this can cause difficulties.
Edit 4: As has been pointed out, it would be trivial to change the HTML such that the visual appearance is the same, but the issue doesn't exist. However, I am trying to find a solution that works with the HTML as written, regardless of how the HTML is written.
demo - http://jsbin.com/tosusanowu/edit?html,js,output
Assuming you know that desired_size div has always a parent that is hidden.
$(function(){
var desired_size = getDesiredSize('#desired_size');
});
function getDesiredSize(el) {
var $el = $(el), $parent = $el.parent(), desired_size = 0;
$parent.attr('style', 'opacity:0;position:absolute');
desired_size = $el.height();
$parent.attr('style', 'display:none');
return desired_size;
}
<div style="display:none;">
...Some random text or other content...
<div id="desired_size">
I want to find the height of this div when visible
</div>
...Possibly some more content/other stuff...
</div>
The following javascript/jQuery function should work in the general case where the HTML structure is unknown, as requested:
function getHeight(objectID){
var object=$('#'+objectID);
var nextObject=object;
var changedObjects=[];
var counter=0; //to prevent infinite looping
while(!object.is(':visible') && counter<100){
counter+=1;
var curObject=nextObject; //store a reference for use in loop
nextObject=curObject.parent();
var curStyle=curObject.css('display') //see if current object is hidden
if(curStyle!='none')
continue; //don't mess with non-hidden objects
//see if the display style is inline, or from a CSS file
var inlineStyles=curObject.attr("style");
if(typeof(inlineStyles)!=='undefined'){
inlineStyles.split(";").forEach(function(element){
var style = element.split(":");
if ($.trim(style[0]) === 'display') {
//Record the fact that the display properly is an inline style
curObject.data('floatinghead_inline_style',true);
return false; //break out of the forEach loop
}
});
}
curObject.show(); //if object is hidden, show it for now
visitedObjects.push(curObject); //save a reference so we can put it back later
}
var height=object.height(); //this should work properly, since object should now be visible
visitedObjects.forEach(function(item){
if(item.data('floatinghead_inline_style')===true)
item.hide();
else
item.css('display','');
})
}
The above code makes no assumptions about the HTML structure, particularly the depth of the object in question from the hidden parent element. Also, unlike the "clone item to a different, visible, location in the DOM" option, it should properly take into account any inherited attributes that affect the height.

Multiple show/hide scrollable containers

In my example here:
Example
JS
$('button').on('click', showHide);
$('.overlay').on('click', showHide);
function showHide(){
$('.scroll-container').toggleClass('show');
$('.content-container').toggleClass('no-scroll');
$('.overlay').toggleClass('opacity');
}
you have a basic body with text. A clickable element (in this case a 'button') causes a scrollable container to appear and 'hover' over the original body, which can be hidden again by clicking outside of this container.
I'm not very good at JavaScript and with this example I was helped by a friend. The thing I'm struggling with now is that I need multiple different clickable elements, displaying a similar scrolling container, but with different content.
I'm doing this for a portfolio website, so imagine a bunch of photos on a page, which when clicked result in a body hovering over the original content, further elaborating the clicked project.
Do I create multiple id's for each project, together with multiple scrolling container id's, and just copy the JavaScript a couple of times?
I hope this makes sense and I hope someone is capable of explaining to me how I'm able to create the proposed effect.
First of all, you have to make a connection between buttons and containers that should be opened. One way is to use their indexes, so that when first button is clicked, first container would open. You can use this reference of the clicked object inside your function, in order to get its index. Like this:
$(this).index()
Then, you have to select all the elements with scroll_container class $('.scroll-container') and reduce the set of matched elements to the one by passing index of the clicked element to .eq() method .eq($(this).index()). Finally, you have to add show class to it addClass('show').
And because the logic is changed, you have to separate actions done on button and .overlay click events. They do not make a reverse action now, so they are not "togglers" anymore.
http://codepen.io/anon/pen/LpWwJL
$('button').on('click', show);
$('.overlay').on('click', hide);
function show(){
$('.scroll-container').eq($(this).index()).addClass('show');
$('.content-container').addClass('no-scroll');
$('.overlay').addClass('opacity');
}
function hide() {
$('.scroll-container').removeClass('show');
$('.content-container').removeClass('no-scroll');
$('.overlay').removeClass('opacity');
}
UPDATE
One thing you should keep in mind regarding $(this).index() method.
As it is written here:
If no argument is passed to the .index() method, the return value is an integer indicating the position of the first element within the jQuery object relative to its sibling elements.
That means that trigger elements should have common parent in order to maintain our logic.
In cases like this: https://stackoverflow.com/posts/32946956/edit, elements that are triggering scroll_container appearance, have different parent nodes (they are placed in 3 different divs). So, if we will call index() method for each of them, it will return '0' because they are the first and the only elements in their parent nodes.
Actually it means that you have to get the order of their parent elements, not theirs own. This can be achieved by using parent() method before index():
$(this).parent().index()
Here is updated codepen.
If I were you, I would implement a generic function to display a different content using the same function based in the button. So for that we will need something to relational the click with the content for that we can set a value in out button:
<button data-id="1">Click me 1!</button>
<button data-id="2">Click me 2!</button>
so out when we click the button we should get the value to send it to our function:
$('button').on('click', function(){
var dataButtonValue = $(this).data('id');
});
Then we can match it with the content using for example data-content-id
<div class="content" data-content-id="1">your wording</div>
<div class="content" data-content-id="2">your wording</div>
With all that we can manage what content we want to show depends on the click.
function showHide(id){
$('.content[data-content-id="' + id + '"]').toggleClass('show');
}
DEMO
I hope it's helps.

Making only a div visible inside an iFrame

I have an iFrame in a html page myPage.html where I am displaying another page otherPage.html. otherPage.html is a complicated page with many elements. I want to display only one div in the iFrame. All the others should remain hidden. How can I do this?
Instead of the iFrame, I tried to use the .load() function in jQuery. But for some reason, the page does not load. The otherPage.html is served from an IIS server and the page is constructed from purely Javascript. I have no idea why nothing is loading when I use the load() function.
How would I go about achieving this?
Update:
Here are some clarifications:
I tried to use the .load() function on myPage.html. Anyway, after fiddling around, I found the following to work:
For the div that I want to show, I hide all its siblings and also hide all the siblings of its parent. The following jQuery statement seems to do this:
$("#myFrame").contents().find("#chart1").show().parentsUntil('body').andSelf().siblings().hide();
I have only one issue now. When I do the following:
Load myPage.html in Firefox (It also loads otherPage.html in an
Iframe)
Manually open firebug and type
$("#myFrame").contents().find("#chart1").show().parentsUntil('body').andSelf().siblings().hide();
it seems to hide everything else.
But then I want to automate it. In other words, when I load myPage.html I want it to load the contents of the iFrame. Once the iFrame contents are loaded I want to then run this script:
$("#myFrame").contents().find("#chart1").show().parentsUntil('body').andSelf().siblings().hide();
I cannot get this to work. I have tried these two approaches so far:
$(document).ready(function() {
$("#myFrame").ready(function () {
$("#myFrame").contents().find("#chart1").show().parentsUntil('body').andSelf().siblings().hide();
});
});
I have also tried to use
$("#myFrame").load(function () {
instead. But in both these cases the script does not hide the other elements. Since, the script works when I use it manually in the console, I assume that somehow it is running before all the elements are loaded. Please give me your thoughts.
Hide everything within the iFrame by something like $("#myIFrame *").hide(); or you can set the css display property to none.
Using CSS selector, re-display only the div you want. If your div has an id this is pretty easy : $('#myDiv').show();
If the div does not have an id, see if you can give it one. If creating an id for your div is not an option, try to give its parent an id/class.
If ID is not an option you may also find selectors like :nth-child() useful.
You say you are using the load() function. Are you using this in the parent page or the iframe page? Do you really mean to use the ready() function instead?
$(document).ready(function(){
// some code here ...
});
Using ready() on the document will ensure that the DOM elements have completely loaded, and then will execute the code in the handler. Without more information I'm not sure I can help much with what you're trying here.
Using an iframe you should first remember that if you want only one div to be visible and all others to be hidden you must make sure that the "visible" div is not inside an "invisible" container. If the container is hidden, all children will be hidden too.
If you had a div "showme", then something like this would work:
<div id="showme">visible text</div>
<div style="display:none;">hidden text</div>
But doing it this way, everything would be hidden:
<div style="display:none;">
hidden text
<div id="showme">supposed to be visible, but hidden!!</div>
</div>
If you are changing the visibility, or display, of an element you can do it in the iframe page like this:
// using jQuery...
// set the display css to an empty string, defaulting to visible (not 'none')
$('#showme').css('display','');
// set other elements to be hidden...
$('#hideme1').css('display','none');
$('#hideme2').css('display','none');
$('#hideme3').css('display','none');
If you want to change the visibility of elements from the PARENT page you first access the iframe, then change the elements within it:
// using jQuery...
// get the iframe. ps. you dont have to put the $ in front of the variable name.
// I chose to do it this way to remind myself it's a jQuery object.
var $f = $('#myiframe').contents();
// set the display css to an empty string, defaulting to visible (not 'none')
$f.find('#showme').css('display','');
// set other elements to be hidden...
$f.find('#hideme1').css('display','none');
$f.find('#hideme2').css('display','none');
$f.find('#hideme3').css('display','none');
See this article for example(s) on working with elements in a child iframe:
http://www.computerhowtoguy.com/jquery-and-iframes/
As I understood your question. You can do like this, pass div id to get displayed as hash in your otherPage.html url like you have a div with id first, you can pass first as hash
<iframe src="otherPage.html#first" />
and in otherPage.html, you can get this hash and according to that show your div, but make first all your sections hidden, using css will be easy, only add "display:none;" in css.
and try this : in otherPage.html
$(function(){
//var divToShow = location.hash.subString(1);
//$('#'+divToShow).show();
var divToShow = location.hash;
$(divToShow).show();
});

Take all elements matching a selector, put them in a dialog, hide everything else on the page

In a dialog, I would like to show all elements with a specific class. The dialog should hide the rest of the page.
So for example: On this Stack Overflow page, I want to show all elements with class="user-info". Those elements would be shown in a dialog with the same width and height and the same CSS and everything else would be hidden. It would be like cutting them out of the page and pasting them in a dialog.
Any ideas how this could be done?
I would like to show in dialog all
elements with specific class.
So clone those elements, e.g.:
var $div = $("<div />").append($(".fooClass").clone()).dialog();
The dialog should hide the rest of the
page.
Either set the overlay graphic (which you can do using themeroller) to something opaque, or attach some code to the open and close events:
$div.dialog({
open: function(event, ui) { $("body").hide() } // that will hide everything, including the dialog, so watch out.
close: function(event, ui) { $("body").show() }
});
Proof of concept here.
EDIT: This demo keeps the inline style defined in a parent element.
Found an answer thanks to this post
Check it out here. It demonstrates pulling all elements of certain class from iframe and than appending them to main document and copying their style. Problem is that its very slow, especially if we copy many elements with a lot of child elements. If anyone knows a way to improve performance let me know (post here:)).
note: The reason I loaded jsFiddle page in iframe is that it(browser?) won't let jquery inspect content of iframe that's not loaded from same domain.

Categories

Resources