Monday, March 5, 2012

Simple PushState in Dart

‹prev | My Chain | next›

Tonight, I try to figure out push state in Dart. Any client-side MVC framework worth its salt needs push state routing and, dammit, Hipster MVC is worth salt.

So I start with an empty page that loads in a Dart script:
  <title>Hipster Push State</title>
  <script type="application/dart"

  <script type="text/javascript">
    // start Dart

<h1>Push that state!</h1>

In that main.dart entry point, I define render() and template() functions:
render(num) {
  var el = document.query('body');
  el.innerHTML = template(num);

template(num) {
  return """
<p>Now we're on page <b>$num</b>.</p>""";
The render() function draws the result of the template in the page so that render('One'); results in:

Next, I define a method that will navigate to a particular page after a given number of seconds:
navAfter(page_number, delay) {
  window.setTimeout(() {
  }, delay * 1000);
If I then define main() to be:
main() {
  navAfter('One', 1);
  navAfter('Two', 2);
  navAfter('Three', 3);
Then, I see page "One", page "Two" and finally page "Three". But the URL remains the same throughout and, if I click back, then I leave this sample app entirely.

So, instead of rendering the page when I nav-after, I route to the correct page:
navAfter(page_number, delay) {
  window.setTimeout(() {
  }, delay * 1000);
This route function then renders the appropriate HTML snippet, but it is also responsible for pushing the current state into History:
route(num) {
  window.history.pushState(null, num, window.location.pathname + "#$num");
With that, I have three different pages in history, but, when I click back to page "Two", I still see page three rendered:

To fix that, I need to start a history listener at the end of my main() entry point:
main() {
  navAfter('One', 1);
  navAfter('Two', 2);
  navAfter('Three', 3);

That history listener is responsible for listening to the window's popState events:
startHistory() {
    add((event) {
      var page_num = window.location.hash.replaceFirst('#', '');
With that, I have the proper page displaying for the current route:

This is not quite ready to be popped into Hipster MVC, but it was a nice way to ease into it.

Day #316

No comments:

Post a Comment