Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.

  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint

Creating CheckoutView

Next, you’ll create the CheckoutView component, which contains the views a user will experience in the checkout process.

1.
Right-click the views package and create a new MXML Component. Leave the Package set as views, give the component a Name of CheckoutView, set the Layout to be spark.layouts.BasicLayout, leave the Based on value as spark.components.Group, and remove the values from the Width and Height fields.

2.
After the end of the layout block, create a states block to hold the states. You’ll use the <s:states> tag (with a lower case s in states), as you are addressing the states property of this new component.

<s:layout>
  <s:BasicLayout/>
</s:layout>
<s:states>

</s:states>

3.
Add three <s:State> (capital S) instances to define the states for the component. The first should have a name of customerInfo, the second billingInfo, and the third review.

<s:states>
  <s:State name="customerInfo"/>
  <s:State name="billingInfo"/>
  <s:State name="review"/>
</s:states>

Here you are defining the three states of this component, which will show the individual views of the Checkout process.

4.
In the Declarations block, create an instance of the valueObject of OrderInfo. Give the instance an id of orderInfo.

<fx:Declarations>
  <!-- Place non-visual elements (e.g., services, value objects) here -->
  <valueObjects:OrderInfo id="orderInfo"/>
</fx:Declarations>

You now have an instance of the OrderInfo class that can be populated by the views to which it is passed. Next you’ll add a few methods to ease the process of navigating between the views.

5.
Create a Script block, and a private variable named currentView, data typed as an int, with a default value of 0.

</s:states>
<fx:Script>
  <![CDATA[
    private var currentView:int=0;
  ]]>
</fx:Script>
<fx:Declarations>

This will be used to keep track of which views users are on, so when they click a next button, you know what view to show them next.

6.
Create a private method named setViewByIndex, which accepts an integer as a parameter and returns void. In the method, create a switch statement that will set the currentState to customerInfo if the value 1 is passed, billingInfo if a 2 is passed, and review if 3 is passed in.

private function setViewByIndex(index:int):void{
  switch(index){
    case 0:
      currentState="customerInfo";
      break;
    case 1:
      currentState="billingInfo";
      break;
    case 2:
      currentState="review";
      break;
  }
}

7.
Create a private method called handleProceed that accepts an event as an argument, and returns void. In this method, increment the value of currentView, and then pass currentView to the setViewByIndex method.

private function handleProceed( event:Event ):void {
  currentView++;
  setViewByIndex(currentView);
}

Now, whenever a proceed event is heard, the currentState will be changed to the next state in the order. Next, you’ll create the CustomerInfo view, and set it to be shown in the proper state.

8.
Right-click the views package and choose new MXML Component. Set the Package to be views.checkout, set the Name to be CustomerInfo, set the Layout to spark.layouts.VerticalLayout, and leave the Based on as spark.components.Group. Remove the Width and Height values. Click Finish.

9.
Add a Label after the closing Declaration tag. Set the text of the Label to be Checkout Page 1 of 3.

10.
Add a Script block after the declarations but before the Label. Declare a public bindable property named orderInfo data typed as valueObject of the OrderInfo.

<fx:Declarations>
  <!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
  <![CDATA[
    import valueObjects.OrderInfo;
    [Bindable]
    public var orderInfo:OrderInfo;
  ]]>
</fx:Script>
<s:Label text="Checkout Page 1 of 3"/>

11.
Open Checkout.mxml from the default package. Copy the entire form from the component. Switch back to CustomerInfo.mxml, and paste the form after the Label tag. Remove the x and y values from the <s:Form> tag.

<s:Label text="Checkout Page 1 of 3"/>
<s:Form >
  <s:FormHeading label="Customer Information"/>
  <s:FormItem label="Customer Name">
    <s:TextInput/>
  </s:FormItem>
  <s:FormItem label="Address">
    <s:TextInput/>
  </s:FormItem>
  <s:FormItem label="City">
    <s:TextInput/>
  </s:FormItem>
  <s:FormItem label="State">
    <s:TextInput/>
  </s:FormItem>
  <s:FormItem label="Zip">
    <s:TextInput/>
  </s:FormItem>
  <s:FormItem>
    <s:Button label="Continue"/>
  </s:FormItem>
</s:Form>

					  

12.
Find the TextInput, which is a child of the first form item (which has a label Customer Name). Set the text property of this TextInput to be a two-way binding to the billingName property of the orderInfo object.

<s:TextInput text="@{orderInfo.billingName}"/>

As discussed earlier in the lesson, this syntax will create a two-way binding, so the control will initially be populated with the value of the billingName property of the orderInfo object, and if the user makes a change, the change will be stored automatically back in the orderInfo object.

13.
Add similar two-way bindings for the text inputs in the Address, City, State, and Zip FormItems. The values you’ll bind to are billingAddress, billingCity, billingState, and billingZip.

<s:Form >
  <s:FormHeading label="Customer Information"/>
  <s:FormItem label="Customer Name">
    <s:TextInput text="@{orderInfo.billingName}"/>
  </s:FormItem>
  <s:FormItem label="Address">
    <s:TextInput text="@{orderInfo.billingAddress}"/>
  </s:FormItem>
  <s:FormItem label="City">
    <s:TextInput text="@{orderInfo.billingCity}"/>
  </s:FormItem>
  <s:FormItem label="State">
    <s:TextInput text="@{orderInfo.billingState}"/>
  </s:FormItem>
  <s:FormItem label="Zip">
    <s:TextInput text="@{orderInfo.billingZip}"/>
  </s:FormItem>
  <s:FormItem>
    <s:Button label="Continue"/>
  </s:FormItem>
</s:Form>

Now your whole form is set to be bound to the billing properties of orderInfo.

14.
Add a click hander on the Continue button, which calls the handleProceed method and passes the event as an argument. With your cursor after the closing parentheses, which are after the word event, press Ctrl-1 and choose Generate event handler.

15.
In the newly created event handler, dispatch an event with the type proceed.

protected function handleProceed(event:MouseEvent):void{
  dispatchEvent( new Event( "proceed" ) );
}

16.
As a final step for this component, add metadata indicating that this class is capable of broadcasting an event with the name proceed and a type of flash.events.Event.

<fx:Metadata>
  [Event(name="proceed", type="flash.events.Event")]
</fx:Metadata>

17.
Save your file.

This completes the CustomerInfo component. The complete source for this component should appear like the following code.

<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
      xmlns:s="library://ns.adobe.com/flex/spark">
  <s:layout>
    <s:VerticalLayout/>
  </s:layout>
  <fx:Declarations>
    <!-- Place non-visual elements (e.g., services, value objects) here -->
  </fx:Declarations>
  <fx:Metadata>
    [Event(name="proceed", type="flash.events.Event")]
  </fx:Metadata>
  <fx:Script>
    <![CDATA[
      import valueObjects.OrderInfo;
      [Bindable]
      public var orderInfo:OrderInfo;

      protected function handleProceed(event:MouseEvent):void{
        dispatchEvent( new Event( "proceed" ) );
      }

    ]]>
  </fx:Script>
  <s:Label text="Checkout Page 1 of 3"/>
  <s:Form >
    <s:FormHeading label="Customer Information"/>
    <s:FormItem label="Customer Name">
      <s:TextInput text="@{orderInfo.billingName}"/>
    </s:FormItem>
    <s:FormItem label="Address">
      <s:TextInput text="@{orderInfo.billingAddress}"/>
    </s:FormItem>
    <s:FormItem label="City">
      <s:TextInput text="@{orderInfo.billingCity}"/>
    </s:FormItem>
    <s:FormItem label="State">
      <s:TextInput text="@{orderInfo.billingState}"/>
    </s:FormItem>
    <s:FormItem label="Zip">
      <s:TextInput text="@{orderInfo.billingZip}"/>
    </s:FormItem>
    <s:FormItem>
      <s:Button label="Continue" click="handleProceed(event)"/>
    </s:FormItem>
  </s:Form>
</s:Group>

					  

Next, you’ll instantiate this component in the CheckoutView component.

18.
Open CheckoutView.mxml. After the closing Declarations tag, add an instance of the CustomerInfo component. Assign a width and height of 100%, bind the orderInfo object to the orderInfo property of the component, listen for the proceed event, and call the handleProceed method you wrote in a previous exercise. Lastly, set this component to be shown only in the customerInfo state, by using the includeIn attribute. The final code for CheckoutView should read like this:

<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
      xmlns:s="library://ns.adobe.com/flex/spark" width="400" height="300" xmln
s:valueObjects="valueObjects.*" xmlns:checkout="views.checkout.*">
  <s:layout>
    <s:BasicLayout/>
  </s:layout>
  <s:states>
    <s:State name="customerInfo"/>
    <s:State name="billingInfo"/>
    <s:State name="review"/>
  </s:states>
  <fx:Script>
    <![CDATA[
      private var currentView:int=0;
      private function setViewByIndex(index:int):void{
        switch(index){
          case 0:
            currentState="customerInfo";
            break;
          case 1:
            currentState="billingInfo";
            break;
          case 2:
            currentState="review";
            break;
        }
      }
      private function handleProceed( event:Event ):void {
        currentView++;
        setViewByIndex(currentView);
      }
    ]]>
  </fx:Script>
  <fx:Declarations>
     <!-- Place non-visual elements (e.g., services, value objects) here -->
     <valueObjects:OrderInfo id="orderInfo"/>
  </fx:Declarations>
  <checkout:CustomerInfo width="100%" height="100%"
     orderInfo="{orderInfo}"
     proceed="handleProceed( event )"
     includeIn="customerInfo"/>
</s:Group>

					  

19.
Save your file. CheckoutView is now equipped to work with your new component. The next step is to instantiate CheckoutView in the main application.

20.
Open FlexGrocer.mxml. After the closing declarations tag, add two states: one called shopping and the other called checkout.

<s:states>
  <s:State name="shopping"/>
  <s:State name="checkout"/>
</s:states>

21.
Just after the bodyGroup instance of the ShoppingView component, create an instance of your CheckoutView component. Set the width and height to 100%. Set the includeIn attribute to only show this component in the checkout state. Set the includeIn for the ShoppingView to be shopping.

<views:ShoppingView id="bodyGroup"
  width="100%" height="100%"
  groceryInventory="{productService.products}"
  shoppingCart="{shoppingCart}"
  includeIn="shopping"/>
<views:CheckoutView width="100%" height="100%"
  includeIn="checkout"/>

22.
Create a new method called startCheckout that accepts a MouseEvent as a parameter and returns void. The body of the function should set the currentState to checkout. Call this function from the click handler of btnCheckout.

protected function startCheckout(event:MouseEvent):void{
  this.currentState="checkout";
}
...
<s:Button id="btnCheckout" y="10" right="10" label="Checkout"
click="startCheckout(event)"/>

23.
Save and run the application. Now, if you click the Checkout button, the application will change states to show the CustomerInfo component.


  

You are currently reading a PREVIEW of this book.

                                                                                                                    

Get instant access to over $1 million worth of books and videos.

  

Start a Free 10-Day Trial


  
  • Safari Books Online
  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint