Saturday, March 29, 2014

AngularJS: Moment + timezone example

At my current workplace, they were using this javascript class to handle the time for different time zones, therefore I have created a simple example to showcase this class. :D

Main HTML file - index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>Moment Timezone</title>
</head>
<!-- stitch this with the module declare in Javascript -->
<body ng-app="myApp">
  <div ng-controller="SelectCtrl">The time in
    <select ng-model="selectedItem" ng-options="item.label for item in myData  | orderBy:'label'" ng-change="updateTime()"></select> is {{formattedTime}}.
  </div>
  <script type="text/javascript" src="js/angular.min.js"></script>
  <script type="text/javascript" src="js/app.js"></script>
  <script type="text/javascript" src="js/controller.js"></script>
  <script type="text/javascript" src="js/moment.min.js"></script>
  <script type="text/javascript" src="js/moment-timezone.min.js"></script>
  <script type="text/javascript" src="js/moment-timezone-data.js"></script>
</body>
</html>

Javascript file that stores the respective time zone data - moment-timezone-data.js
//The data of the time zone of the various time zone.
tzData = {
    "zones": {
        "Asia/Singapore": [
            "6:55:25 - LMT 1901_0_1 6:55:25",
            "6:55:25 - SMT 1905_5_1 6:55:25",
            "7 - MALT 1933_0_1 7",
            "7:20 - MALST 1936_0_1 7:20",
            "7:20 - MALT 1941_8_1 7:20",
            "7:30 - MALT 1942_1_16 7:30",
            "9 - JST 1945_8_12 9",
            "7:30 - MALT 1965_7_9 7:30",
            "7:30 - SGT 1982_0_1 7:30",
            "8 - SGT"
        ],
        "Australia/Sydney": [
            "10:4:52 - LMT 1895_1 10:4:52",
            "10 Aus EST 1971 10",
            "10 AN EST"
        ],
        "EST5EDT": [
            "-5 US E%sT"
        ],
        "Europe/Amsterdam": [
            "0:19:32 - LMT 1835 0:19:32",
            "0:19:32 Neth %s 1937_6_1 1:19:32",
            "0:20 Neth NE%sT 1940_4_16_0 0:20",
            "1 C-Eur CE%sT 1945_3_2_2 1",
            "1 Neth CE%sT 1977 1",
            "1 EU CE%sT"
        ],
        "Europe/London": [
            "-0:1:15 - LMT 1847_11_1_0 -0:1:15",
            "0 GB-Eire %s 1968_9_27 1",
            "1 - BST 1971_9_31_2",
            "0 GB-Eire %s 1996",
            "0 EU GMT/BST"
        ]
    },
    "rules": {
        "Aus": [
            "1917 1917 0 1 7 0:1 0 1",
            "1917 1917 2 25 7 2 0 0",
            "1942 1942 0 1 7 2 0 1",
            "1942 1942 2 29 7 2 0 0",
            "1942 1942 8 27 7 2 0 1",
            "1943 1944 2 0 8 2 0 0",
            "1943 1943 9 3 7 2 0 1"
        ],
        "AN": [
            "1971 1985 9 0 8 2 2 1",
            "1972 1972 1 27 7 2 2 0",
            "1973 1981 2 1 0 2 2 0",
            "1982 1982 3 1 0 2 2 0",
            "1983 1985 2 1 0 2 2 0",
            "1986 1989 2 15 0 2 2 0",
            "1986 1986 9 19 7 2 2 1",
            "1987 1999 9 0 8 2 2 1",
            "1990 1995 2 1 0 2 2 0",
            "1996 2005 2 0 8 2 2 0",
            "2000 2000 7 0 8 2 2 1",
            "2001 2007 9 0 8 2 2 1",
            "2006 2006 3 1 0 2 2 0",
            "2007 2007 2 0 8 2 2 0",
            "2008 9999 3 1 0 2 2 0",
            "2008 9999 9 1 0 2 2 1"
        ],
        "US": [
            "1918 1919 2 0 8 2 0 1 D",
            "1918 1919 9 0 8 2 0 0 S",
            "1942 1942 1 9 7 2 0 1 W",
            "1945 1945 7 14 7 23 1 1 P",
            "1945 1945 8 30 7 2 0 0 S",
            "1967 2006 9 0 8 2 0 0 S",
            "1967 1973 3 0 8 2 0 1 D",
            "1974 1974 0 6 7 2 0 1 D",
            "1975 1975 1 23 7 2 0 1 D",
            "1976 1986 3 0 8 2 0 1 D",
            "1987 2006 3 1 0 2 0 1 D",
            "2007 9999 2 8 0 2 0 1 D",
            "2007 9999 10 1 0 2 0 0 S"
        ],
        "Neth": [
            "1916 1916 4 1 7 0 0 1 NST",
            "1916 1916 9 1 7 0 0 0 AMT",
            "1917 1917 3 16 7 2 2 1 NST",
            "1917 1917 8 17 7 2 2 0 AMT",
            "1918 1921 3 1 1 2 2 1 NST",
            "1918 1921 8 1 8 2 2 0 AMT",
            "1922 1922 2 0 8 2 2 1 NST",
            "1922 1936 9 2 0 2 2 0 AMT",
            "1923 1923 5 1 5 2 2 1 NST",
            "1924 1924 2 0 8 2 2 1 NST",
            "1925 1925 5 1 5 2 2 1 NST",
            "1926 1931 4 15 7 2 2 1 NST",
            "1932 1932 4 22 7 2 2 1 NST",
            "1933 1936 4 15 7 2 2 1 NST",
            "1937 1937 4 22 7 2 2 1 NST",
            "1937 1937 6 1 7 0 0 1 S",
            "1937 1939 9 2 0 2 2 0",
            "1938 1939 4 15 7 2 2 1 S",
            "1945 1945 3 2 7 2 2 1 S",
            "1945 1945 8 16 7 2 2 0"
        ],
        "C-Eur": [
            "1916 1916 3 30 7 23 0 1 S",
            "1916 1916 9 1 7 1 0 0",
            "1917 1918 3 15 1 2 2 1 S",
            "1917 1918 8 15 1 2 2 0",
            "1940 1940 3 1 7 2 2 1 S",
            "1942 1942 10 2 7 2 2 0",
            "1943 1943 2 29 7 2 2 1 S",
            "1943 1943 9 4 7 2 2 0",
            "1944 1945 3 1 1 2 2 1 S",
            "1944 1944 9 2 7 2 2 0",
            "1945 1945 8 16 7 2 2 0",
            "1977 1980 3 1 0 2 2 1 S",
            "1977 1977 8 0 8 2 2 0",
            "1978 1978 9 1 7 2 2 0",
            "1979 1995 8 0 8 2 2 0",
            "1981 9999 2 0 8 2 2 1 S",
            "1996 9999 9 0 8 2 2 0"
        ],
        "EU": [
            "1977 1980 3 1 0 1 1 1 S",
            "1977 1977 8 0 8 1 1 0",
            "1978 1978 9 1 7 1 1 0",
            "1979 1995 8 0 8 1 1 0",
            "1981 9999 2 0 8 1 1 1 S",
            "1996 9999 9 0 8 1 1 0"
        ],
        "GB-Eire": [
            "1916 1916 4 21 7 2 2 1 BST",
            "1916 1916 9 1 7 2 2 0 GMT",
            "1917 1917 3 8 7 2 2 1 BST",
            "1917 1917 8 17 7 2 2 0 GMT",
            "1918 1918 2 24 7 2 2 1 BST",
            "1918 1918 8 30 7 2 2 0 GMT",
            "1919 1919 2 30 7 2 2 1 BST",
            "1919 1919 8 29 7 2 2 0 GMT",
            "1920 1920 2 28 7 2 2 1 BST",
            "1920 1920 9 25 7 2 2 0 GMT",
            "1921 1921 3 3 7 2 2 1 BST",
            "1921 1921 9 3 7 2 2 0 GMT",
            "1922 1922 2 26 7 2 2 1 BST",
            "1922 1922 9 8 7 2 2 0 GMT",
            "1923 1923 3 16 0 2 2 1 BST",
            "1923 1924 8 16 0 2 2 0 GMT",
            "1924 1924 3 9 0 2 2 1 BST",
            "1925 1926 3 16 0 2 2 1 BST",
            "1925 1938 9 2 0 2 2 0 GMT",
            "1927 1927 3 9 0 2 2 1 BST",
            "1928 1929 3 16 0 2 2 1 BST",
            "1930 1930 3 9 0 2 2 1 BST",
            "1931 1932 3 16 0 2 2 1 BST",
            "1933 1933 3 9 0 2 2 1 BST",
            "1934 1934 3 16 0 2 2 1 BST",
            "1935 1935 3 9 0 2 2 1 BST",
            "1936 1937 3 16 0 2 2 1 BST",
            "1938 1938 3 9 0 2 2 1 BST",
            "1939 1939 3 16 0 2 2 1 BST",
            "1939 1939 10 16 0 2 2 0 GMT",
            "1940 1940 1 23 0 2 2 1 BST",
            "1941 1941 4 2 0 1 2 2 BDST",
            "1941 1943 7 9 0 1 2 1 BST",
            "1942 1944 3 2 0 1 2 2 BDST",
            "1944 1944 8 16 0 1 2 1 BST",
            "1945 1945 3 2 1 1 2 2 BDST",
            "1945 1945 6 9 0 1 2 1 BST",
            "1945 1946 9 2 0 2 2 0 GMT",
            "1946 1946 3 9 0 2 2 1 BST",
            "1947 1947 2 16 7 2 2 1 BST",
            "1947 1947 3 13 7 1 2 2 BDST",
            "1947 1947 7 10 7 1 2 1 BST",
            "1947 1947 10 2 7 2 2 0 GMT",
            "1948 1948 2 14 7 2 2 1 BST",
            "1948 1948 9 31 7 2 2 0 GMT",
            "1949 1949 3 3 7 2 2 1 BST",
            "1949 1949 9 30 7 2 2 0 GMT",
            "1950 1952 3 14 0 2 2 1 BST",
            "1950 1952 9 21 0 2 2 0 GMT",
            "1953 1953 3 16 0 2 2 1 BST",
            "1953 1960 9 2 0 2 2 0 GMT",
            "1954 1954 3 9 0 2 2 1 BST",
            "1955 1956 3 16 0 2 2 1 BST",
            "1957 1957 3 9 0 2 2 1 BST",
            "1958 1959 3 16 0 2 2 1 BST",
            "1960 1960 3 9 0 2 2 1 BST",
            "1961 1963 2 0 8 2 2 1 BST",
            "1961 1968 9 23 0 2 2 0 GMT",
            "1964 1967 2 19 0 2 2 1 BST",
            "1968 1968 1 18 7 2 2 1 BST",
            "1972 1980 2 16 0 2 2 1 BST",
            "1972 1980 9 23 0 2 2 0 GMT",
            "1981 1995 2 0 8 1 1 1 BST",
            "1981 1989 9 23 0 1 1 0 GMT",
            "1990 1995 9 22 0 1 1 0 GMT"
        ]
    },
    "links": {}
};

moment.tz.add(tzData);

Javascript file that stores our AngularJS Application - app.js
// declare a module
var myApp = this.angular.module('myApp', ['myAppControllers']);
Javascript file that stores our Angularjs Controllers - controller.js
// declare a controller
angular.module('myAppControllers', []).
  controller('SelectCtrl', function ($scope) {
    //the selections for the time zone drop down
    $scope.myData = [{
      label: "Singapore",
      value: "Asia/Singapore"
    }, {
      label: "Sydney",
      value: "Australia/Sydney"
    }, {
      label: "EST5EDT",
      value: "EST5EDT"
    }, {
      label: "Amsterdam",
      value: "Europe/Amsterdam"
    }, {
      label: "London",
      value: "Europe/London"
    }];

 //Preselect the first item in the array
    $scope.selectedItem = $scope.myData[0];
    $scope.formattedTime = "";
    $scope.timer;
 //This function will pick up the selected item from the
 //drop down and display the corresponding time of the
 //time zone
    $scope.updateTime = function () {
   var tempDate;
   var strTz = $scope.selectedItem.value;
      tempDate = moment.tz(strTz);
      $scope.formattedTime = tempDate.format('MMMM Do YYYY, h:mm:ss a');
   $scope.$apply();
    }
    $scope.updateTime();
 //We will run the function updateTime every second
    setInterval(function () {
      $scope.updateTime()
    }, 1000);
  });
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.
~ Click here to find out more about 'AngularJS'.
* Click here to find out more about 'moment.js'.
^ Click here to find out more about 'Moment Timezone'.
~ Click here to generate the data for the respective time zone for 'Moment Timezone'.

Saturday, March 22, 2014

Flex 4: Accessing the renderers of a DataGroup

There might be situations where you might be creating a list of items in a horizontal or vertical manner. And you might be using a <DataGroup> to get things done. But after you have successfully created a list, you might have to disable 1 of the items, but how are you going to access the individual items of the <DataGroup>? I hope that this post would give an idea on how do access the individual item of a <DataGroup>.

Source Code for the main application - 'SimpleDataGroup.mxml'
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx" 
      width="100%" 
      height="100%" 
      creationComplete="creationCompleteEvent(event)">
 <fx:Script>
  <![CDATA[
   import events.RendererEvent;
   
   import mx.collections.ArrayCollection;
   import mx.events.FlexEvent;
   
   import renderers.HorizontalRenderer;
   import renderers.VerticalRenderer;
   
   private var dataArray:Array = [{
    label: 'Item 1',
    value: 'A'
   },{
    label: 'Item 2',
    value: 'B'
   },{
    label: 'Item 3',
    value: 'C'
   },{
    label: 'Item 4',
    value: 'D'
   },{
    label: 'Item 5',
    value: 'E'
   },{
    label: 'Item 6',
    value: 'F'
   },{
    label: 'Item 7',
    value: 'G'
   },{
    label: 'Item 8',
    value: 'H'
   }];
   
   //Our Data
   [Bindable]
   private var dataCollection:ArrayCollection = 
    new ArrayCollection(dataArray);
   
   //This will be our simple result text string.
   [Bindable]
   private var resultStr:String = "";
   
   protected function creationCompleteEvent(event:FlexEvent):void
   {
    this.addEventListener(RendererEvent.RENDERER_CLICK_EVENT,
     clickEvent);
   }
   
   //Upon clicking on one of the buttons, we will loop through
   //all the buttons in the DataGroup and change their state
   //accordingly.
   private function clickEvent(event:RendererEvent):void
   {
    var tempHRenderer:HorizontalRenderer;
    var tempVRenderer:VerticalRenderer;
    for(var i:int = 0; i < hData.numElements; i ++)
    {
     tempHRenderer = 
      HorizontalRenderer(hData.getElementAt(i));
     if(tempHRenderer.data.label == event.label)
     {
      tempHRenderer.currentState = "selected";
     }else{
      tempHRenderer.currentState = "init";
     }
    }
    for(i = 0; i < vData.numElements; i ++)
    {
     tempVRenderer = 
      VerticalRenderer(vData.getElementAt(i));
     if(tempVRenderer.data.label == event.label)
     {
      tempVRenderer.currentState = "click";
      resultStr = "You have click on the button " +
       "labeled '" + tempVRenderer.data.label + 
       "' with a value of '" + 
       tempVRenderer.data.value + "'";
     }else{
      tempVRenderer.currentState = "norm";
     } 
    }
   }
  ]]>
 </fx:Script>
 <s:VGroup width="100%" 
     height="100%" 
     horizontalAlign="center" 
     verticalAlign="middle">
  <s:Label text="Try clicking on a button."/>
  <s:DataGroup width="100%" 
      id="hData"
      dataProvider="{dataCollection}"
      itemRenderer="renderers.HorizontalRenderer">
   <s:layout>
    <s:HorizontalLayout gap="0" 
         verticalAlign="middle" 
         horizontalAlign="center"/>
   </s:layout>
  </s:DataGroup>
  <s:DataGroup width="100%"
      id="vData"
      dataProvider="{dataCollection}"
      itemRenderer="renderers.VerticalRenderer">
   <s:layout>
    <s:VerticalLayout gap="0"
          verticalAlign="middle" 
          horizontalAlign="center"/>
   </s:layout>
  </s:DataGroup>
  <s:Label text="{resultStr}"/>
 </s:VGroup>
</s:Application>

And here's the custom event class for the renderers - 'RendererEvent.as'
package events
{
 import flash.events.Event;
 
 public class RendererEvent extends Event
 {
  //We will dispatch this event when we 
  //click on a renderer.
  public static const RENDERER_CLICK_EVENT:String = 
   "RenderClickEvent";
  
  //Used to stores the label 
  public var label:String = "";
  
  public function RendererEvent
   (type:String, 
    bubbles:Boolean=false, 
    cancelable:Boolean=false, 
    _label:String="")
  {
   super(type, bubbles, cancelable);
   label = _label;
  }
  
  override public function clone():Event
  {
   return new RendererEvent(type, 
    false, 
    false, 
    label);
  }
 }
}

And here's the horizontal item renderer - 'HorizontalRenderer.mxml'
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    autoDrawBackground="true" 
    mouseChildren="false" 
    click="clickHandler(event)" 
    buttonMode="true">
 
 <fx:Script>
  <![CDATA[
   import events.RendererEvent;
   
   //When we click on this Renderer, 
   //we will dispatch an event.
   protected function clickHandler(event:MouseEvent):void
   {
    this.dispatchEvent(
     new RendererEvent(
      RendererEvent.RENDERER_CLICK_EVENT, 
      true, 
      false, 
      this.data.label));
   }
  ]]>
 </fx:Script>
 <s:states>
  <s:State name="init"/>
  <s:State name="selected"/>
 </s:states>
 <s:BorderContainer height="30" 
        width="80">
  <s:backgroundFill.init>
   <s:LinearGradient rotation="90">
    <s:GradientEntry color="0xFFFFFF"/>
    <s:GradientEntry color="0xCCCCCC"/>
   </s:LinearGradient>
  </s:backgroundFill.init>
  <s:backgroundFill.selected>
   <s:LinearGradient rotation="90">
    <s:GradientEntry color="0xFFFFCC"/>
    <s:GradientEntry color="0xCCFF99"/>
   </s:LinearGradient>
  </s:backgroundFill.selected>
  <s:borderStroke> 
   <mx:SolidColorStroke 
    color="black" 
    weight="1"/> 
  </s:borderStroke>
  <s:VGroup width="100%" 
      height="100%"
      horizontalAlign="center"
      verticalAlign="middle">
   <s:Label text="{data.label}"
      color="0x000000"/>
  </s:VGroup>
 </s:BorderContainer>
</s:ItemRenderer>

And here's the vertical item renderer - 'VerticalRenderer.mxml'
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    autoDrawBackground="true" 
    mouseChildren="false" 
    click="clickHandler(event)" 
    buttonMode="true">
 
 <fx:Script>
  <![CDATA[
   import events.RendererEvent;
   
   //When we click on this Renderer, 
   //we will dispatch an event.
   protected function clickHandler(event:MouseEvent):void
   {
    this.dispatchEvent(
     new RendererEvent(
      RendererEvent.RENDERER_CLICK_EVENT, 
      true, 
      false, 
      this.data.label));
   }
  ]]>
 </fx:Script>
 <s:states>
  <s:State name="norm"/>
  <s:State name="click"/>
 </s:states>
 <s:BorderContainer height="30" 
        width="80">
  <s:backgroundFill.norm>
   <s:LinearGradient rotation="90">
    <s:GradientEntry color="0xCCCCCC"/>
    <s:GradientEntry color="0x666666"/>
   </s:LinearGradient>
  </s:backgroundFill.norm>
  <s:backgroundFill.click>
   <s:LinearGradient rotation="90">
    <s:GradientEntry color="0xCCFFFF"/>
    <s:GradientEntry color="0x00FFCC"/>
   </s:LinearGradient>
  </s:backgroundFill.click>
  <s:borderStroke> 
   <mx:SolidColorStroke 
    color="black" 
    weight="1"/> 
  </s:borderStroke>
  <s:VGroup width="100%" 
      height="100%" 
      horizontalAlign="center" 
      verticalAlign="middle">
   <s:Label text="{data.label}"
      color.norm="0xFFFFFF"
      color.click="0x000000"/>
  </s:VGroup>
 </s:BorderContainer>
</s:ItemRenderer>
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.

Wednesday, March 12, 2014

AngularJS: Select + Option in Angular

If you are going to use a <select> element in your website that is going to build on top of AngularJS, rather than using a mixture of <select> and <option> element, it would be best if you use a combination of <select> and the attribute 'ng-options'. As for the reason why, you can take a look at the demo below, and take a look at it again across browsers like 'Internet Explorer 8/9', 'Mozilla Firefox', etc...


* Click here to access the demo that I have created on 'JSFiddle'.
^ Click here to test your JavaScript, CSS, HTML or CoffeeScript online with JSFiddle code
  editor.

Tuesday, March 4, 2014

AngularJS: Alternate Background Row Styles

When you have a table with fixed contents, it is pretty easy for you to apply styling that applies different set of styles on alternate table rows. However, things get more and more tricky when you are hiding and showing some of the rows. Therefore, here's a simple example that I have created using 'AngularJS' that helps you to overcome the problem of alternate background styles + hidden rows.


* Click here to access the demo that I have created on 'JSFiddle'.
^ Click here to test your JavaScript, CSS, HTML or CoffeeScript online with JSFiddle code
  editor.