Skip to content

Lesson 09 Dynamic Loading with ViewStack

Roland Zwaga edited this page Jul 31, 2013 · 3 revisions

Please Note: There is a new plugin version available which requires an SDK change, please read for more details.

In this lesson, you will use a pre-built Randori behavior named ViewStack. ViewStack is a common way to manage an area of your application in which multiple views will be shown; however, only one view will be show at a time.

The ViewStack understands how to perform the dynamic loading of your view’s html, and then asks Randori to perform the same steps outlines in previous lessons to build the newly loaded content.

With Randori, everything starts with a URL to an HTML file. After that HTML file is loaded, Randori decorates with the requisite functionality allowing it to become interactive.

  1. Ensure you have the SimpleTest project open in IntelliJ

  2. Open behaviors.css from the assets folder

  3. Add the following viewStack class selector to the bottom of the css file. Then save the file.

    .viewStack {
      -randori-behavior: "randori.behaviors.ViewStack";
    }

    This adds a behavior for the ViewStack class, which is part of the Randori framework

  4. Switch to the index.html

  5. Below the existing messageWindow div, add a new input tag with the id loadMore and type button as show below:

    <body class="simpleApp">
      <div id="messageWindow" class="messageWindow">
        <div id="title">Simple Test</div>
        <div id="message">My Message</div>
      </div>
      <input id="loadMore" value="Load More" type="button"/>
    </body>
  6. Below the new input, add a new div with an id of myViewStack and a class attribute of viewStack. Although this code would eventually be better placed inside of a style declaration, also set relative positioning on the ViewStack as follows:

    <body class="simpleApp">
      <div id="messageWindow" class="messageWindow">
        <div id="title">Simple Test</div>
        <div id="message">My Message</div>
      </div>
      <input id="loadMore" value="Load More" type="button"/>
      <div id="myViewStack" class="viewStack" style="position:relative"/>
    </body>

    You are simply decorating that div with a ViewStack behavior.

  7. Right click on your SimpleTest project and create a top level Directory named views

  8. Inside of the views directory, create a new HTML file called people.html

  9. Inside the body of people.html, just add the text: This is people

    <body>
      This is people
    </body>
  10. Open the IndexMediator class.

  11. Add a public variable named loadMore of type JQuery and decorate it with View metadata

    [View]
    public var loadMore:JQuery;
    

    You are requesting that the loadMore input defined in your HTML file be injected here.

  12. Add a public variable named myViewStack of type ViewStack and decorate it with View metadata

    [View]
    public var myViewStack:ViewStack;
    

    You are requesting that the ViewStack behavior defined in your HTML file be injected here.

  13. In your initialize() method, below the existing code, add a click handler to the loadMore input using JQuery.

    loadMore.click( handleLoadMore );
    

    You will notice as you are typing that there are several click() methods. Right now these are named numerically but a superior naming convention will be provided shortly. ActionScript does not have method overloading and this is exactly the use case where it is needed.

  14. Create a new private handleLoadMore() method which takes an event of type randori.jquery.Event as follows:

    private function handleLoadMore( event:Event ):void {
    }
  15. This provides an excellent opportunity to talk about cleanup. Just below your initialize() method, override a protected function named destroy().

    override public function destroy():void {
    }

    The destroy() method is the opposite of the initialize() it is called anytime a behavior is being removed from the DOM. You are expected to clean up your own mess in this method. The destroy() of a parent is called just before the destroy() of child behaviors.

  16. Inside the destroy() method, cleanup the event listener on the loadMore input:

    override public function destroy():void {
      loadMore.off("click");
    }
  17. Inside of the handleLoadMore() method, you will call the pushView() method of the ViewStack instance and pass the url to the people.html file.

    private function handleLoadMore( event:Event ):void {
      myViewStack.pushView("views/people.html")
    }

    The ViewStack works by pushing and popping views. When a view is pushed, the view is loaded and Randori does all the work to instantiate the view. Loading a view is an asynchronous operation and you may need a way to respond after the operation completes. To that end, Randori provides a Promises/A+ compliant implementation which is used for asynchronous operations.

  18. Assign the result of calling pushView() to a new variable of type Promise from the randori.async package.

    private function handleLoadMore( event:Event ):void {
      var promise:Promise = myViewStack.pushView("views/people.html")
    }

    Be cautious with this step. As is often the case, there are multiple Promises implementations using the same name but in different packages. For example, JQuery also provides a promises implementation (in the randori.jquery package); however, it is not necessarily compliant. Ensure you use the one from the randori.async package.

  19. Use the then() method of the promise to log something to the console when the view is resolved as shown below.

    private function handleLoadMore( event:Event ):void {
      var promise:Promise = myViewStack.pushView("views/people.html");
    
      promise.then( function(mediator:AbstractMediator):void {
        Window.console.log("Got it");
      } );
    }

    The promise will return the AbstractMediator associated with your new view. Your console.log() will then execute once the view is completely ready.

    For any type of production code, you should always check for the existence of Window.console before actually calling log. The console does not exist when IE is not in debug mode, meaning your code works in

    debug and fails in production.

  20. Save, build and run your code. When you press the load more button, it should load the people view below.

  21. Right click on the mediators package and create a new mediator named PeopleMediator

  22. Open the behavior.css from the assets folder.

  23. Add the a class selector called peopleView for the new mediator you just created

    .peopleView {
      -randori-mediator: "mediators.PeopleMediator";
    }
  24. While still in the css file, also add a new class selector called simpleList for the Randori simple list class as shown below:

    .simpleList {
      -randori-behavior: "randori.behaviors.SimpleList";
    }
  25. Open people.html, add a class attribute and specify peopleView on the body.

    <body class="peopleView">
      This is people
    </body>
  26. Next, eliminate the text this is people and replace it with an unordered list as show in the code below:

    <body class="peopleView">
      <ul>
      </ul>
    </body>
  27. Assign the unordered list the class simpleList and give it an id of names

    <body class="peopleView">
      <ul id="names" class="simpleList">
      </ul>
    </body>

    This will make decorate the unordered list as a simple list.

  28. Inside of the unordered list, add a list element with an id of template as the following code shows:

    <body class="peopleView">
      <ul id="names" class="simpleList">
        <li id="template"></li>
      </ul>
    </body>

    This will specify the HTML fragment that Randori will use as a template.

  29. Finally, specify that you want to show the name field from the data which will be provided to the list.

    <body class="peopleView">
      <ul id="names" class="simpleList">
        <li id="template">{name}</li>
      </ul>
    </body>

    The Randori templating engine is very simple. It can accept a field name, a dot-expression to find the field name from the object root, or an *, meaning the entire object. It can be used in combination with other techniques to become more complex but is intended for simple use cases.

  30. Return to the PeopleMediator. Add a public var called names of type SimpleList. Decorate it with the View metadata.

    [View]
    public var names:SimpleList;
    
  31. Inside the initialize() method create a couple of simple objects with a name property and add them to an array as the following code shows:

    override public function initialize():void {
      var o1:Object = {name:"Mike"};
      var o2:Object = {name:"Roland"};
      var ar:Array = [o1,o2];
    }

    Yes, this is just temporary. In the next lesson, you will get this data from a remote service.

  32. Finally, assign the array instance to the data property of the SimpleList instance:

    override protected function initialize():void {
      var o1:Object = {name:"Mike"};
      var o2:Object = {name:"Roland"};
      var ar:Array = [o1,o2];
      names.data = ar;
    }
  33. Save, build and run your app.

When you press the load more button, you will see your people.html file is loaded. Randori finds the dynamic behaviors and mediators associated with this file and instantiates those as well, resulting in a list appearing in that area.

In the next lesson, you will learn more about interacting with the viewstack.