3

I am trying to show a busy waiting icon at the point of ajax invocation (i.e., event.target or object that fired the event). I use the following code to achieve that but in some cases the position (offset) of the element returned is top:0 and left:0 - I know I'm probably making a mistake but can't seem to nail it. Here's my code (It's in a backbone view class, but that shouldn't matter since it's quite trivial):

//ajax loading animation
var LoadingAnimation = Backbone.View.extend({

    tagName: 'div', //creates an empty div element

initialize: function() {
    var DOMElement = this.options.DOMElement; //is passed as a param (see below)
    var pos = DOMElement.offset();  //<-- pos.left and pos.top 0 for some elements??
    var _width = DOMElement.outerWidth(true);
    var _height = DOMElement.outerHeight(true);

            //setting the 'style' of 'this' div     
    $(this.el).css({
        "position":"absolute", 
        "left" : pos.left+"px",
        "top"  : pos.top+"px",
        "z-index" : 9999,
        "width" : _width+"px",
        "height": _height+"px",
        "background": "#FFFFFF url(images/loading_round.gif) no-repeat center center"
        });

            /*appending to body. Don't know if this is correct, but nothing would 
             *show if it was not done :(
             */

    $('body').append(this.el);

    //_.bindAll(this, 'render','unrender'); //ignore for now
    this.render();
},

render: function() {
    $(this.el).show();
},

unrender: function() {
    $(this.el).fadeOut("slow");
    $(this.el).remove();
}

});

Here's how it can be invoked:

$('.ajaxAble').click(function(event){

var showBusy = new LoadingAnimation({DOMElement:$(this)}); //create and render busy waiting

//do ajax calls here and call showBusy.unrender() in success/error

}

This works fine for some elements but for some the offset() returns 0. I don't know why though? All of those elements have relative positioning and the div to be shown has absolute. But I don't see the conflict. (Is there one?). I need to make this class as position agnostic as possible, so to speak...

PS: I chose the local non-blocking way as pointed out in this post: Best way to have 'busy waiting' animation be 'position configurable' in jquery? (i.e., show it where the action is)

UPDATE: (After selecting answer): Tom's answer of appending to parent of DOMElement is correct. However for that to work properly it's better to use .position() rather than .offset() above (as suggested by rkw). The above code appends to body (incorrect for some elements) but uses offset.

Community
  • 1
  • 1
PhD
  • 11,202
  • 14
  • 64
  • 112

3 Answers3

1

The result of position:relative will depend on the position of the parent. If you're applying this behavior to a diverse collection of items, it may be the case that their positioning context is sufficiently different to cause the behavior you're seeing.

Is the problem you're seeing reproducible? And is it always the same for the same elements?

EDIT: here's the code you need to append the new loading indicator to the page, at a place in the document where the position info you got earlier will make sense.

// $('body').append(this.el);
$(DOMElement).parent().append(this.el);
Tom
  • 8,509
  • 7
  • 49
  • 78
1

An absolutely-positioned item finds its origin at the first RELATIVELY POSITIONED parent element. If none if defined it will go up the tree to the BODY tag.

The only time you need to define position:relative is when you wish to define that element as the new origin point for its CHILD elements.

Diodeus - James MacFarlane
  • 112,730
  • 33
  • 157
  • 176
  • Yup. And maybe that's the problem? Is it because I'm appending to the body the problems are arising?? – PhD Aug 08 '11 at 21:03
  • If you want the item to be positioned relative to the body, then that's ok. If it's not, choose the correct containing DIV. – Diodeus - James MacFarlane Aug 08 '11 at 21:14
  • Well not exactly. I have a bunch of nested divs on the page. It's just that the animation wasn't even showing up until I appended it to an existing DOM element (body in this case). I don't know if it's correct to do that though and hence I pointed it out – PhD Aug 08 '11 at 21:16
1

To standardize against all browsers, I would recommend the methods available through jQuery:

.offset(): Use this if you want the position relative to the page

.position(): Use this if you want the position relative to the parent element. Note that for this one to work, your parent element must have either a position: relative or position: absolute property.

rkw
  • 7,287
  • 4
  • 26
  • 39
  • I tried using `.position()` but for some reason I get zeroes for everything! :) – PhD Aug 08 '11 at 21:04
  • the element that is holding your animation needs to have position: relative for it's css property. – rkw Aug 08 '11 at 21:08