Behavior Version

Creating a behavior version is often even easier than creating a regular version. One of the reason is that it is easier to initialize and the second is that it allows you to have setters and getters for properties. And of course behaviors are way more easier to reuse than non encapsulated scripts.

Defining Properties

I wanted two properties and I decided to call them syncTo and syncDirection. Both have the type String and syncTo should be assigned the id of the component that you want to sync to. Notice that you should not do forward referencing because the target might not have been loaded yet. syncDirection is a simple property with no code for handling setting and getting but syncTo has both a setter and a getter. When you set the property it should remove any old attached event listeners as well as add a new listener. The getter just returns the value of a private variable called _syncTo.

The xml structure of the HTML component looks like this

<?xml version="1.0" encoding="utf-8" ?> 

<public:component lightWeight="true">
<public:property name="syncTo" put="setSyncTo" get="getSyncTo" />
<public:property name="syncDirection" />
<script language="JScript">
//<[[CDATA[


...

//]]>
</script>
</public:component>

In the property element I've set the name of the setter and getter (put and get) functions and the set function looks like this:

function setSyncTo(sToElementId) {
   // remove old sync to
   if (oSyncTo != null)
      oSyncTo.detachEvent("onscroll", onScroll);

   sSyncTo = sToElementId;
   // look up the element with sToElementId in the real html document
   oSyncTo = element.document.getElementById(sToElementId);

   if (oSyncTo != null)
      oSyncTo.attachEvent("onscroll", onScroll);
}

Notice how we look up the oSyncTo element in the main document and also notice that we now can set the function to handle the event directly. This is because the all variables and functions in the htc file are private.

The onScroll function has become a little bit easier but the logic is exactly the same and the removeScrollSync equivalent is not needed anymore. (We could have created the non behavior version without it as well.)

function onScroll() {
   if (syncDirection == "horizontal" || syncDirection == "both")
      element.scrollLeft = event.srcElement.scrollLeft;
   if (syncDirection == "vertical" || syncDirection == "both")
      element.scrollTop = event.srcElement.scrollTop;
}

Setting up the page

Add the behavior in the usual way. I'll do it in a script block.

#div1 {
   border: 1px solid black;
   padding: 2px;
   overflow: auto;
   width: 100px;
   height: 100px;
}

#div2 {
   behavior: url("syncscroll.htc");
   border: 1px solid black;
   padding: 2px;
   overflow: hidden;
   width: 100px;
   height: 100px;
}

And then create the divs and set the custom attributes on the second one.

<div id="div1">
   Fill container...
</div>

<div id="div2" syncTo="div1" syncDirection="both">
   Fill container...
   (This one will be synchronized with the one above)
</div>

That's it. As you can see this is a lot easier to use and maintain. If you change any of the properties the state will reflect this.

Demo

I've recreated the first demo using behaviors. I also added a check box that toggles the syncTo property of div4 at runtime to show that it works to turn it on and off.

Show me the demo

Notice

You have to fill the containers with something to make them scroll. The scrollLeft value will never exceed the scrollWidth - clientHeight. This means that once you've reached the right edge no more scrolling will occur. The same applies to scrollTop of course.

Synchronized Scroll
Demo without behavior
Behavior version
Behavior version demo
Scrollable Table
Scrollable Table Demo
Download this sample

Author: Erik Arvidsson