Link to home
Start Free TrialLog in
Avatar of Marco Gasi
Marco GasiFlag for Spain

asked on

Problems getting a div scrolled to list item

Hi everybody.
I'm workin on an application with get a list of contacts from both Gmail and Outlook: the code works fine and for each account I get my beautyful list filled with contacts. Since the list is huge, I placed on top a navigation built on alphabet: the goal is to allow the user to click a letter and jump directly to the first item whose email starts with that letter.

This is the markup:
function fetch(token) {
	var listOwner;
	listOwner = 'Your contacts from Gmail';
	jQuery('#list-owner').text(listOwner);
	jQuery('#sharing-mail-contacts').slideDown();
	jQuery.ajax({
		url: "https://www.google.com/m8/feeds/contacts/default/full?access_token=" + token.access_token + "&max-results=1000&alt=json",
		dataType: "jsonp",
		success: function (contacts) {
			console.log(contacts);
			if ( contacts['feed']['entry'] !== '' ) {
				var profileImageUrl, emailOwner, emailAddress;
				var email_array = [];
				for ( var i = 0;i < contacts['feed']['entry'].length;i++ ) {
					if ( contacts['feed']['entry'][i]['gd$email'] != null ) {
						emailAddress = contacts['feed']['entry'][i]['gd$email'][0]['address'];
						if ( contacts['feed']['entry'][i]['title']['$t'] != null &&
										contacts['feed']['entry'][i]['title']['$t'] != '' ) {
							emailOwner = contacts['feed']['entry'][i]['title']['$t'];
						} else {
							emailOwner = '';
						}
						email_array.push(emailAddress + '#' + emailOwner);
					}
				}
				email_array.sort();
				var first_letter;
				for ( var i = 0;i < email_array.length;i++ ) {
					var els = email_array[i].split('#');
					var new_first_letter = els[0].substring(0, 1).toLowerCase();
					if ( new_first_letter != first_letter )
					{
						first_letter = new_first_letter;
						var html = '<li class="contacts" id="' + first_letter + '"><a name="' + first_letter + '"><input name="checkboxG5" id="checkbox' + i + '" value="' + els[0] + '" class="css-checkbox" type="checkbox"><label for="checkbox' + i + '" class="css-label"><span class="contact-address">' + els[0] + '</span> <span class="contact-name">(' + els[1] + ')</span></label></a><li>';
						if ( html !== '' ) {
							jQuery('#mail-contacts').append(html);
						}
					} else {
						var html = '<li class="contacts"><input name="checkboxG5" id="checkbox' + i + '" value="' + els[0] + '" class="css-checkbox" type="checkbox"><label for="checkbox' + i + '" class="css-label"><span class="contact-address">' + els[0] + '</span> <span class="contact-name">(' + els[1] + ')</span></label><li>';
						if ( html !== '' ) {
							jQuery('#mail-contacts').append(html);
						}
					}
				}
				jQuery('#mail-contacts li').each(function () {
					if ( jQuery(this).html() === '' ) {
						jQuery(this).remove();
					}
				});
				jQuery('#contacts-wrapper').mCustomScrollbar();
			}
		}
	});
}

Open in new window

At line 27 I check for the first letter of emaiol address: if the first letter appears for the first time I set for that ite an unique id.
Here's the markup:
<div id="sharing-mail-contacts">
	<div id="contacts-header">
		<img class="img-responsive" src="assets/sat_images/user-logo.png" /><img class="img-responsive" src="assets/sat_images/logo.png" /><span id="list-owner"></span>
	</div>
	<p id="contacts-tip">Please, select the contacts you want share the card with and press 'Share this card' button to send them your card image.</p>
	<p>
		<a class="alpha" href="#a">A</a>&nbsp;
		<a class="alpha" href="#b">B</a>&nbsp;
		<a class="alpha" href="#c">C</a>&nbsp;
		<a class="alpha" href="#d">D</a>&nbsp;
		<a class="alpha" href="#e">E</a>&nbsp;
		<a class="alpha" href="#f">F</a>&nbsp;
		<a class="alpha" href="#g">G</a>&nbsp;
		<a class="alpha" href="#h">H</a>&nbsp;
		<a class="alpha" href="#i">I</a>&nbsp;
		<a class="alpha" href="#j">J</a>&nbsp;
		<a class="alpha" href="#l">L</a>&nbsp;
		<a class="alpha" href="#m">M</a>&nbsp;
		<a class="alpha" href="#n">N</a>&nbsp;
		<a class="alpha" href="#o">O</a>&nbsp;
		<a class="alpha" href="#p">P</a>&nbsp;
		<a class="alpha" href="#q">Q</a>&nbsp;
		<a class="alpha" href="#r">R</a>&nbsp;
		<a class="alpha" href="#s">S</a>&nbsp;
		<a class="alpha" href="#y">T</a>&nbsp;
		<a class="alpha" href="#u">U</a>&nbsp;
		<a class="alpha" href="#v">V</a>&nbsp;
		<a class="alpha" href="#w">W</a>&nbsp;
		<a class="alpha" href="#x">X</a>&nbsp;
		<a class="alpha" href="#y">Y</a>&nbsp;
		<a class="alpha" href="#z">Z</a>
	</p>
	<div id="contacts-wrapper">
		<ul id="mail-contacts">

		</ul>
	</div>
</div>

Open in new window

When the contacts are fetched the ul #mail-contacts is filled with data.
Then, I tried several solution to scroll to the selected item. As you can see, I tried to use anchors, but this, though it work, looks bad, even the whle body scrolls down and if I click in another part of the page the list scrolls up again.
So I created the ids and used this code:
jQuery('.alpha').on('click', function (e) {
	e.preventDefault();
	var letter = jQuery(this).text().toLowerCase();
	var aTag = jQuery("li."+letter).first();
	jQuery(aTag).get(0).scrollIntoView();
});

Open in new window


or
	var letter = jQuery(this).text().toLowerCase();
	var container = jQuery('#contacts-wrapper');
	var scrollTo = jQuery("li#" + letter);
	console.log('container top '+container.offset().top);
	console.log('scroll top '+scrollTo.offset().top);
	container.animate({scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop()});
});

Open in new window

and even this brutal, desperate code:
jQuery('.alpha').on('click', function (e) {
	e.preventDefault();
	var container = jQuery('#contacts-wrapper');
	container.scrollTop(960);
});

Open in new window

Where set up, in console I see values for offset().top, but the list remains fixed.
Thank you for any help :-)
Cheers
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

I'm not sure any JavaScript is needed.  IIRC, I did this once before with only HTML.  Let me see if I can give you an example...  Back in a little while :-)
Avatar of Marco Gasi

ASKER

Hi Ray. Well, without javascript I used an anchor
<a name=['a']></a>

Open in new window

You can see it in the snippet when I use the variable first_letter (starting at line 27). That gave me a bad result, as I said, but I hopefully wait for your lighning example :-)
Don't worry about the PHP wrapper - it's not necessary for the demonstration, just my way of keeping track of the code snippets.
<?php // demo/temp_marqusg.php
/**
 * https://www.experts-exchange.com/questions/28941631/Problems-getting-a-div-scrolled-to-list-item.html
 *
 */
error_reporting(E_ALL);
$htm = <<<EOD

<div id="sharing-mail-contacts">
	<div id="contacts-header">
		<img class="img-responsive" src="assets/sat_images/user-logo.png" /><img class="img-responsive" src="assets/sat_images/logo.png" /><span id="list-owner"></span>
	</div>
	<p id="contacts-tip">Please, select the contacts you want share the card with and press 'Share this card' button to send them your card image.</p>
	<p>
		<a class="alpha" href="#a">A</a>&nbsp;
		<a class="alpha" href="#b">B</a>&nbsp;
		<a class="alpha" href="#c">C</a>&nbsp;
		<a class="alpha" href="#d">D</a>&nbsp;
		<a class="alpha" href="#e">E</a>&nbsp;
		<a class="alpha" href="#f">F</a>&nbsp;
		<a class="alpha" href="#g">G</a>&nbsp;
		<a class="alpha" href="#h">H</a>&nbsp;
		<a class="alpha" href="#i">I</a>&nbsp;
		<a class="alpha" href="#j">J</a>&nbsp;
		<a class="alpha" href="#l">L</a>&nbsp;
		<a class="alpha" href="#m">M</a>&nbsp;
		<a class="alpha" href="#n">N</a>&nbsp;
		<a class="alpha" href="#o">O</a>&nbsp;
		<a class="alpha" href="#p">P</a>&nbsp;
		<a class="alpha" href="#q">Q</a>&nbsp;
		<a class="alpha" href="#r">R</a>&nbsp;
		<a class="alpha" href="#s">S</a>&nbsp;
		<a class="alpha" href="#y">T</a>&nbsp;
		<a class="alpha" href="#u">U</a>&nbsp;
		<a class="alpha" href="#v">V</a>&nbsp;
		<a class="alpha" href="#w">W</a>&nbsp;
		<a class="alpha" href="#x">X</a>&nbsp;
		<a class="alpha" href="#y">Y</a>&nbsp;
		<a class="alpha" href="#z">Z</a>
	</p>
	<div id="contacts-wrapper">
		<ul id="mail-contacts">

<li id="a">A</a><br>Content<br>Content<br>Content<br><br></li>
<li id="b">B</a><br>Content<br>Content<br>Content<br><br></li>
<li id="c">C</a><br>Content<br>Content<br>Content<br><br></li>
<li id="d">D</a><br>Content<br>Content<br>Content<br><br></li>
<li id="e">E</a><br>Content<br>Content<br>Content<br><br></li>
<li id="f">F</a><br>Content<br>Content<br>Content<br><br></li>
<li id="g">G</a><br>Content<br>Content<br>Content<br><br></li>
<li id="h">H</a><br>Content<br>Content<br>Content<br><br></li>
<li id="i">I</a><br>Content<br>Content<br>Content<br><br></li>
<li id="j">J</a><br>Content<br>Content<br>Content<br><br></li>
<li id="l">L</a><br>Content<br>Content<br>Content<br><br></li>
<li id="m">M</a><br>Content<br>Content<br>Content<br><br></li>
<li id="n">N</a><br>Content<br>Content<br>Content<br><br></li>
<li id="o">O</a><br>Content<br>Content<br>Content<br><br></li>
<li id="p">P</a><br>Content<br>Content<br>Content<br><br></li>
<li id="q">Q</a><br>Content<br>Content<br>Content<br><br></li>
<li id="r">R</a><br>Content<br>Content<br>Content<br><br></li>
<li id="s">S</a><br>Content<br>Content<br>Content<br><br></li>
<li id="y">T</a><br>Content<br>Content<br>Content<br><br></li>
<li id="u">U</a><br>Content<br>Content<br>Content<br><br></li>
<li id="v">V</a><br>Content<br>Content<br>Content<br><br></li>
<li id="w">W</a><br>Content<br>Content<br>Content<br><br></li>
<li id="x">X</a><br>Content<br>Content<br>Content<br><br></li>
<li id="y">Y</a><br>Content<br>Content<br>Content<br><br></li>
<li id="z">Z</a><br>Content<br>Content<br>Content<br><br></li>

		</ul>
	</div>
</div>

EOD;

echo $htm;

Open in new window

Yes I did it me too that way, but I find two issue:
1) - entire body scrolls down whereas I would like only the scrolling container div scroll: take a look at my markup
<div id="sharing-mail-contacts">
	<div id="contacts-header">
		<img class="img-responsive" src="assets/sat_images/user-logo.png" /><img class="img-responsive" src="assets/sat_images/logo.png" /><span id="list-owner"></span>
	</div>
	<p id="contacts-tip">Please, select the contacts you want share the card with and press 'Share this card' button to send them your card image.</p>
	<p>
		<a class="alpha" href="#a">A</a>&nbsp;
               ...
	</p>
	<div id="contacts-wrapper"> <-- this has overflow auto -->
		<ul id="mail-contacts">
                    <-- here the list -->
		</ul>
	</div>
</div>

Open in new window

Shpould I set overflow: auto for the <ul> element itself instead of for the container?

2) - If user moves the mouse wheel, the list suddenly scrolls to the top
Ahh, I see.  Didn't know you only wanted the div to scroll.  I'll think about this a little more (or maybe someone else will come along with a good answer).
Couple of remarks:

* you remove empty li's, this is probably not necessary, look at what you add: <li>...<li> at the end should be </li> (both times)

* you use a custom scrollbar? that seems related to your issue!

* I tested with a bunch of generated li's and the second click code works fine (the first one just has "." instead of "#") test page here: http://schutt.nl/ee/Q_28941631
ASKER CERTIFIED SOLUTION
Avatar of Robert Schutt
Robert Schutt
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Robert.
I'm going to check everything. Unfortunately, I'm not sure I can replace the custom scroll bar plugin, I have to check that.
I'll come back asap with the response :-)
I've made a simple test version including that scrollbar, note that the "link-letters" are now generated (into p#letters) and the click version is a stripped down version of the one on their website. New test page here: http://schutt.nl/ee/Q_28941631/index2.htm
Bingo! Robert, great solution.
First, good eye for having noticed the opening li tag replacing the closing one.
Second, I had tried to drop out the custom scrollbar but in the pletora of tests, evidently I didn't  test the right code without the plugin: the second code works fine without plugin as you said.
Third, yes the plugin is the one you linked above and yes, I should read plugin documentation, sometime :-)
Thank you!
Thank you
I take advatage of your knowledge :-) Can you take a look at this question too? https://www.experts-exchange.com/questions/28941628/Google-contacts-API-returns-empty-names.html
Lol, hope that green is just Photoshop!
I'll have a look at that one after dinner but not sure I will be able to help.

LOL indeed, no it's not Photoshop, that is how I looked a couple of years ago for St Patrick's day going to the Irish pub.