This blog is all about ways I’m working to streamline my development. Here is one library my colleague introduced that I’ve decided to port to Connect.
Slightly relevant to my last post. This library will speed up my process a bit with its validation and Twitter Bootstrap capabilities. Still working on publishing my whole development stack for Node.js apps. Stay tuned!
I’ve used a lot of database abstractions (from Hibernate to Doctrine to ActiveRecord to Mongoose) over the years and the one thing I continually find myself introducing is this Model->Form and Form->Model abstraction that I like to call a bridge. Sometimes it’s the simplest of abstractions that save a developer the most time.
abstract class AbstractBridge {
protected $model;
protected $form;
public function __construct(Model $model, Form $form) { ... }
public function setModel(Model $model) { ... }
public function setForm(Form $form) { ... }
abstract public function getModel();
abstract public function getForm();
}
The concept is super simple: given this populated form, build me a model – or, conversely, given this database populated model, build me a form object. With PHP’s magic setters and getters, the implementation might look something like this:
public function getModel() {
foreach($this->getFields() as $field) {
$this->model->$field = $this->form->{$field}->getValue();
}
return $this->model;
}
public function getForm() {
foreach($this->getFields() as $field) {
$this->form->{$field}->setValue($this->model->$field);
}
return $this->form;
}
As business logic becomes more complex or you encounter specific use cases, you can further specialize your bridges out from there. Perhaps your form object shouldn’t know about certain members of your model. Or maybe you need to perform some sort of transformation going from form to model. It’s as simple as creating a specialized bridge. If you’d like to introduce validation, it can live on either side of the abstraction, but I often choose to handle mine with the form object just because it’s closest to the user layer and I can easily throw out validation messages… that’s another topic for another time.
One popular technique I see popping up all over in modern web development is the sticky div. A sticky div (if there is a better term for this out there, please leave a comment!) is simply a div that is initially positioned relative but becomes fixed when scrolled past. A prime example of a sticky div can be found on Facebook’s feed; as you scroll down the feed, there is an adzone that initially scrolls normal but becomes fixed after you pass a certain threshold. Ads are important business, so to let this scroll out of view would be bad!

An even more popular and noticeable sticky div can be found on Pinterest. Scroll just 44px and you’ll notice that the main navigation panel sticks. Pretty cool.

Achieving this behavior is pretty simple: bind an event to window.onscroll that monitors the scroll top of the current window relative to the top offset of the div you’d like to stick and throw a fixed class on the element. Seems easy enough, but what happens when you have multiple sticky divs on a page? That can get a bit computationally heavy for an onscroll event.
We can introduce something game developers have been using for years called an Interval Tree. A good Interval Tree will yield O(log n). A quick search for an Interval Tree in JavaScript brought me to this library by Shin Suzuki. It appears to be a centered Interval Tree which yields O(log n + m), where m is the number of reported results, but that should be perfect for our purposes. So, to begin we’ll build up our Interval Tree with the scrollable intervals for where we want our divs to be fixed.
var itree = new IntervalTree(500);
itree.add([0,$('.sticky:first').offset().top, -1]);
var stickies = $('.sticky');
for(var i=0; i<stickies.size(); i++){
var top = stickies.eq(i).offset().top;
var bottom = (i+1 == stickies.size()) ? $(document).height() : stickies.eq(i+1).offset().top;
itree.add([top, bottom, i]);
}
Since this is a centered interval list, I’m just going to provide a center of 500. If I were to throw this into an actual site, I’d probably just take the average height of the site and divide by two. The next line identifies a zone where nothing will be stuck. The interval list add call just takes an array defined as [top, bottom, id]. Id in this case will be in the index of my collection of sticky divs. Now lets define our onscroll event:
var current;
$(document).scroll(function(e) {
var found = itree.search(document.body.scrollTop).shift();
if(found && current != found.data[2]) {
stickies.filter('.fixed').removeClass('fixed');
current = found.data[2];
if(current != -1) {
stickies.eq(current).addClass('fixed');
}
}
});
Easy peasy. I’ve never attempted any benchmarking on any sticky div techniques using a scroll event, so this may be overkill, but at least you now know a use for an interval tree! See a quick demo at: Sticky Div Interval Tree Test.
Design by Simon Fletcher. Powered by Tumblr.
© Copyright 2012, Josh Hundley.