Retrieve DIV values after ResizeEnd

I am trying to return the new TOP and BOTTOM values for a DIV after it has been resized, but after I resize the values returned are the same as what they were before the resize. Am I missing something obvious here?

<div style="position:absolute; width:50px; top:100px; bottom:300px; left:100px; background-color:yellow; border:solid 1px silver;" e:behavior="b:resize" resizeConstraint=".." resizeEdges="top bottom" resizeGripSize="5" xmlns="http://www.w3.org/1999/xhtml" xmlns:e="http://www.backbase.com/2006/xel" xmlns:b="http://www.backbase.com/2006/btl">

    <e:handler event="resizeStart" type="application/javascript">
        startTop = this.viewNode.style.top;
        startBottom = this.viewNode.style.bottom;
    </e:handler>

    <e:handler event="resizeEnd" type="application/javascript">
        <![CDATA[

       alert('startTop='+startTop);
       alert('after resizeEnd top='+this.viewNode.style.top);
       alert('startBottom='+startBottom);
       alert('after resizeEnd bottom='+this.viewNode.style.bottom);
   
       // are we resizing the top or bottom?

       if (startTop != this.viewNode.style.top) {
           alert('top');
       } else if (startBottom != this.viewNode.style.bottom) {
           alert('bottom');
       } else {
           alert('neither');
       }    

       ]]>                
    </e:handler>
   
</div>

Thanks,
Chris

element positioning

You should use either the 'top' or 'bottom' attributes when setting the vertical position of an element, but not both. So, in the example above, I'd suggest removing bottom="300px" and replacing it with height="200px".

To get the height of the div (in pixels) you can use the offsetHeight property e.g. this.viewNode.offsetHeight.

Try again

Unfortunately that didn't help. I have simplified the example. To start out TOP=100px ... and when you resize the DIV by pulling the top it returns TOP=100px again even though it has obviously moved.

<div style="position:absolute; width:50px; top:100px; height:200px; left:100px; background-color:red;" e:behavior="b:resize" resizeConstraint=".." resizeEdges="top" resizeGripSize="5" >

    <e:handler event="resizeEnd" type="application/javascript">
       alert("top BEFORE resize = 100px\ntop AFTER resize =" + this.viewNode.style.top);      
    </e:handler>
   
</div>

--Chris

Looks like a bug

Hi Chris,

Thanks for the simplified test case. It looks like the resizeEnd event fires before the effects of the resize are actually applied to the element (e.g. when you increase the height of the div in the test case and release the mouse button, the gray 'overlay' is still visible behind the alert).

This seems like a bug to me.

As a workaround, you could try using a setTimeout within the resizeEnd handler.

<div style="position:absolute; width:50px; top:100px; height:200px; left:100px; background-color:red;" e:behavior="b:resize" resizeConstraint=".." resizeEdges="top" resizeGripSize="5" >
   <e:handler event="resizeEnd" type="application/javascript">
      var oDiv = this;
      var oMyFunc = function() {
         alert("before = 100px\nafter =" + oDiv.viewNode.style.top);
      }
      setTimeout(oMyFunc, 0);
   </e:handler>
</div>

The setTimeout function will not execute until the resize code has completely finished, by which time the 'top' property of the div will have been set.

Note that you cannot use 'this' inside a setTimeout to refer to the div, hence the oDiv variable.

Re: Looks like a bug

Ok ... thanks for the work around ... that seems to do the trick.

<div style="position:absolute; width:50px; top:100px; height:200px; left:100px; background-color:red;" e:behavior="b:resize" resizeConstraint=".." resizeEdges="top" resizeGripSize="5" >
   <e:handler event="resizeEnd" type="application/javascript">
      var self = this;

      setTimeout(function() {
         alert("before = 100px\nafter =" + self.viewNode.style.top);
      }, 0);
   </e:handler>
</div>

--Chris

Re: Looks like a bug

Well the simple example works but the bit more complex example doesn't ... hopefully it is something small that I am missing. I am trying to do exactly what the simple example is doing, but dynamically creating the DIV via javascript ... is there something I am missing? It doesn't even fire the alert message.

<e:script type="text/javascript">
<![CDATA[

function AddDiv() {

var sHTML = '<div style="position:absolute; width:50px; top:100px; height:200px; left:100px; background-color:red; " e:behavior="b:resize" resizeConstraint=".." resizeEdges="top" resizeGripSize="5" xmlns="http://www.w3.org/1999/xhtml" xmlns:e="http://www.backbase.com/2006/xel" xmlns:b="http://www.backbase.com/2006/btl">' +
                     '    <e:handler event="resizeEnd" type="application/javascript">' +
                     '        alert("here"); ' +
                     '        var self = this; ' +
                     '        setTimeout(function() { ' +
                     '            alert("before = 100px\nafter =" + self.viewNode.style.top); ' +
                     '        //}, 0); ' +
                     '    </e:handler>' +
                     '</div>';

var oXml = bb.xml.parse(sHTML).documentElement;
bb.command.create(oXml, bb.document.getElementById('container'));
}

]]>
</e:script>

<div id="container" style="position:relative; width:300px; height:400px; background-color:tan;"></div>

<b:button>
    Add DIV
    <e:handler event="click" type="application/javascript">
        AddDiv();
    </e:handler>
</b:button>

--Chris

Try this

With a couple of small changes to the string concatenation your example seems to work okay. I replaced the "\n" with ", " and removed the "//" from "//}, 0); ' +".

                     '    <e:handler event="resizeEnd" type="application/javascript">' +
                     '        alert("here"); ' +
                     '        var self = this; ' +
                     '        setTimeout(function() { ' +
                     '            alert("before = 100px, after =" + self.viewNode.style.top); ' +
                     '        }, 0); ' +
                     '    </e:handler>' +

That Did It

That worked ... thanks Nick

Actually using setTimeout is

Actually using setTimeout is not a proper solution. It makes the code asynchronous and possible also inconsistent.

Proper solution here is to use the properties exposed on the resizeEnd event object. The resizeEnd fires before the actual resize happens because then you can prevent the default resize action and do your own calculations / actions to set the width / height / left / top.

Unfortunately those properties are not yet documented (but next release they will).

Example:

<div style="position:absolute; width:50px; top:100px; height:200px; left:100px; background-color:red;" e:behavior="b:resize" resizeConstraint=".." resizeEdges="top" resizeGripSize="5" >

    <e:handler event="resizeEnd" type="application/javascript">
       alert("top BEFORE resize = "+(event.originalTop - event.offsetTop)+"\ntop AFTER resize =" + (event.newTop - event.offsetTop));      
    </e:handler>
   
</div>