Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome's offset() returns null values for option

I cannot calculate the offset position of an option within a select:

<select multiple="true">
    <option>asdf</option>
    <option id="bar">qwer</option>
</select>

$("#bar").offset()

Chrome returns (any jQuery versions like 1.7.2, 1.9 tested):

{top: 0, left: 0} 

FF returns:

{top: 26, left: 9}

I need the positions like FF returns. Is there a workaround for Chrome?

http://jsfiddle.net/YrRLx/

like image 650
Chris Avatar asked Mar 12 '13 09:03

Chris


1 Answers

Ah... one solution I can think of is replacing the select with ul object, and attach event handlers to sync select to ul. Calling .offset() on li elements works as expected on both FF and Chrome.

So if you click the li elements, it will update its background color and update the selected value of the hidden select. This way, when form is submitted, correct value is sent.

http://jsfiddle.net/hqYqh/

HTML:

<select id="mySelect" multiple="true">
    <option>2011</option>
    <option>2012</option>
    <option>2013</option>
    <option>2014</option>
    <option>2015</option>
    <option>2016</option>
    <option>2017</option>
    <option>2018</option>
    <option>2019</option>
</select>

CSS:

ul.select {
    display: inline-block;
    border: 1px solid black;
    list-style: none;
    margin: 0;
    padding: 2px;
    height: 80px;
    overflow: auto;
    width: 50px;
}

ul.select li {
    background-color: none;
    cursor: pointer;
}

ul.select li.selected {
    background-color: skyblue;
}

JS:

var $select = $('#mySelect');
var $ul = $('<ul class="select">').on('click', 'li', function() {
    $(this).parent().find('li').removeClass('selected');
    $(this).addClass('selected');
    $select.val($(this).text()).change();
});

$select.find('option').each(function() {
    var $li = $('<li>').text($(this).text());
    $ul.append($li);
});

$select.hide().after($ul);

$select.change(function() {
    alert('Offset of ' + $(this).val() + ' is ' + JSON.stringify($('li.selected').offset()));
});

EDITED

So, I tried another method following Huangism's suggestion using offset() and scrollTop() of the select element.

Only thing that's not available is the height of the option element. So I tried to estimate using font-size, but it wasn't perfect, and I had to add magic number 3 on Chrome to get the exact offsets. If you can figure out the height of the option element, you don't have to deal with all the ul/li business above.

Here it is:

http://jsfiddle.net/hqYqh/2/

optionOffset = function($option) {
    var i = $option.index();
    var h = Number($option.css('font-size').replace(/px/, '')) + 3; // Cannot get the height of the option element :(
    var $select = $option.parent();
    var offset = $select.offset();
    offset.top += i*h - $select.scrollTop();
    return offset;
}
like image 141
haejeong87 Avatar answered Sep 20 '22 13:09

haejeong87