If you’re not a programmer, move along, there’s nothing to see here. Only programmers will understand what I’m writing about here.
As you might already be aware, I post the results of my genealogy research on this website. So far, I’ve been using the “Narrated Web Site” feature of Gramps. But since I’ve never been totally satisfied with it, I’ve always toyed with the idea of coming up with a better way to present my data. So finally, about a month ago, I started work on a new project, a different way to present my genealogy data.
This is turning out to be a rather ambitious project, with elements coded in Python, PHP, and JavaScript, as well as CSS and HTML. Sometimes it’s hard keeping all the different languages straight. Since I’m using dynamically-generated HTML, most of the challenges are in the JavaScript code, an area that I’m certainly not expert in. In this missive, I discuss some of the lessons I’ve learned while coding, some after much flailing about. I won’t dive too deeply into specific details. You can learn more with the right Google search.
When to register click handlers
First, since I make heavy use of dynamic HTML, I make good use of click handlers. But while coding, I noticed that in some situations, the click handlers weren’t working as expected. It took a bit of digging, and I found a solution I wasn’t totally happy with. Digging further, I then realized something important about registering click handlers when using dynamic HTML: You need to register the click handler after adding the HTML to the DOM. In the cases where they weren’t firing as expected, the handlers were registered first.
Handling history
When using static HTML page, you don’t have to worry about history. The browser does it all automatically. However, with dynamic HTML, you need to manually keep track of the history if you want meaningful navigation through your content. This is achieved by coding an “onpopstate” event handler, as well as calls to functions “pushState()” and “replaceState()”.
After some flailing about, I stepped back and studied the issue in a bit more detail. And I realized it really wasn’t so bad. I just needed to keep track of three specific situations when displaying page content.
First, when moving to a new page, you need to call “pushState” while outputting the new content. That registers the new page in the history stack.
Second, when navigating to a page previously displayed using an “onpopstate” handler (invoked when the user presses the “back” or “forward” button), you just have to output the page content. No further action is needed.
Finally, there’s “replaceState()”. That’s used in situations where you want to update the content currently on the screen, but you don’t want to advance further in the history. For example, you may just want to switch to a different tab in your content. Or perhaps you want to present a table of search results ordered by name instead of date. These are cases where, when pressing the “back” button, you don’t want to go back through these different views. In this type of situations, you call “replaceState()”.
Querying attributes of HTML elements
The final lesson regards querying certain attributes of HTML elements. I’m now getting into an interesting piece of JavaScript programming where I need to know the real sizes of some HTML elements. There are some functions in jQuery to get the size of an element: “outerHeight()” and “outerWidth()”. I tried calling them, and was surprised to get zeroes as the result.
Again, a bit of digging on-line, and I found the answer. Immediately after adding dynamic elements to the DOM, the attributes might not be set yet. Processing the elements must wait until they are ready. So you’ll need to code something like:
jQuery('#mysection').ready( function() {
process_section();
});
I tried this, and I did get non-zero values for the height and width. However, the values returned did not take into account the size of an embedded image. Taking this approach further requires waiting until all embedded images are loaded. Grrr!
I ended up deciding that this avenue was just too strewn with potential problems. I stepped back and decided to take a different approach to what I wanted to do, an approach with a lot fewer complications.
In addition, further research turn up another issue: This usage of the “ready()” function is deprecated by jQuery.
Conclusion
There’s a lot to JavaScript coding. It’s an incredibly complicated and potentially intimidating environment. I’m constantly looking things up on-line: in manuals, on-line courses, or other blogs. However, on-line information, while usually correct, is sometimes missing some important detail that a novice JavaScript programmer might not be aware of that’s needed to make full sense of the information.
Cheers! Hans