Wednesday, June 8, 2016

[Angular-ui-bootstrap] datepickerPopup and timepicker

 #AngularJS   #ui-bootstrap   #datepicker   #timepicker


▌Introduction


Angular-ui-bootstrap 提供了以bootstrap為主的 directives.
以下記錄其中兩個directive的實際應用。

l   datepicker-popup
l   timepicker



▌Environment

l   AngularJS 1.4.8
l   angular-ui-bootstrap 1.3.3

注意! 由於angular-ui-bootstrap使用了很多template html,在ui-bootstrap.js檔裡面定義了這些Html的路徑。 如果不想一個一個去更改路徑的話,可直接引用 ui-bootstrap-tpls.js





▌Implement


完成畫面














▋HTML - datepickerPopup

<p class="input-group">
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open()">
        <i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
<input type="text" class="form-control" ng-click="open()" uib-datepicker-popup ng-model="ScheduleDatetime" is-open="popup.opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
</p>


其中比較重要的是datepicker-options是這個參數,它指定了要設定的格式; 可以參考 javascript的部分。


▋HTML - timepicker

<uib-timepicker ng-model="ScheduleDatetime" ng-change="changed()" hour-step="hstep" minute-step="mstep" show-meridian="ismeridian"></uib-timepicker>


hour-step 和 minute-step是指定使用”上”、”下”按鈕每次累加的數字。
show-meridian: 是否顯示AM/PM; 如果為false就代表是 24小時制。


▋JS

angular.module('app', ['ui.bootstrap'])
.controller('DateTimeCtrl', function ($scope) {

    /*
     * Datepicker
     */
    $scope.today = function () {
        $scope.ScheduleDatetime = new Date();
    };

    $scope.today();

   
    $scope.dateOptions = {
        dateDisabled: disabled, //指定不能選擇星期幾,例如此例的 0 : Sunday, 6 : Saturday
        formatYear: 'yy',
        maxDate: new Date(2020, 5, 22), //The max day that could be selected
        minDate: new Date(), //The min day that could be selected
        startingDay: 1  //Starting from 1. Monday, 2. Tuesday (2) …
    };

    // Disable weekend selection
    function disabled(data) {
        var date = data.date,
          mode = data.mode;
        return mode === 'day' && (date.getDay() === 0 || date.getDay() === 6);
    }


    $scope.open = function () {
        $scope.popup.opened = true;
    };


    $scope.popup = {
        opened: false
    };

    /*
     * Timepicker
     */
    $scope.ismeridian = true;
    $scope.hstep = 1;
    $scope.mstep = 15;
});


PS. 只要指定datepickerPopup和timepicker是同一個ngModel,則angular會自動將日期和時間一起指定給這個ngModel。


最後,如果是從後端丟到前端的日期時間,例如.NET的System.DateTime,一定要在前端先轉成javascript的Date!  如下例,我先用razor帶出後端的ViewBag.defaultDatetime : System.DateTime

為了要正確顯示於前端,利用ConvertDate 這個函式,將其轉換為javascript date。
最後再用$filter顯示為 “2016-06-08 02:09:11”

l   HTML

@{
     var scheduleDatetime = ViewBag.defaultDatetime == null ?
     DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") : ViewBag.defaultDatetime.ToString("yyyy/MM/dd HH:mm:ss");
}

<td><label class="control-label">設定的日期時間</label></td>
<td colspan="2">
    <input type="text" name="ScheduleDatetime" value="{{ScheduleDatetime | date:'yyyy-MM-dd HH:mm:ss'}}" ng-init="ScheduleDatetime = ConvertDate('@scheduleDatetime')" />
</td>


l   JS

//Convert string (ex. yyyy/MM/dd HH:mm:ss) to a javascript datetime
$scope.ConvertDate = function (dateStr) {
        var date = new Date(dateStr);
        return date;
}



▌Reference


Thursday, June 2, 2016

[AngularJS] Connect deirectives

 AngularJS   Directive  



▌Background


There a lot of situations that we might use multiple directives in a webpage, and they have some relations among them. In this example, I created two directives and CONNECTED them.

 

The key point is passing ngModel with two-way binding between these directives.


▋Related article



▌Implement


Refer to the following picture, I have 2 drop-down-lists and 1 display label.
1.  Regions
2.  Cities
3.  What companies in the selected city


 

▋Regions

l   HTML

<select ng-model="Region" ng-change="ChangeChargeId()" ng-options="option.Name for option in RegionOptions track by option.Id" />

l   JS

var app = angular.module('app', [])
  .controller('AppCtrl', function ($scope) {
      $scope.RegionOptions = [{
          'Id': 1,
          'Name': 'North Taiwan'
      }, {
          'Id': 2,
          'Name': 'South Taiwan'
      }];
  })



▋Cities

Create a directive for “Cities”. However, the cities drop-down-list would be changed after the “Region” changes. So we pass the $scope.Region to the isolated scope of the directive for two-way binding.

l   HTML

<my-city ng-model="Region" selectcity="MyCity" />


l   JS

app.directive('myCity', function ($filter) {
        return {
            //restrict: "A",
            scope: {
                Region: "=ngModel",
                selectcity: "="
            },
            template: "<select ng-model='City' ng-change='ChangeCity()' ng-options='option.Name for option in CityOptions track by option.Id' />",
            link: function ($scope, $element) {

                $scope.filterCities = function (regionId) {
                    var cityOpts = $filter('filter')($scope.AllCityOptions, {
                        RegionId: regionId
                    }, true);
                    $scope.CityOptions = cityOpts;
                }

                $scope.AllCityOptions = [
                    { 'Id': 1, 'Name': 'Taipei', 'RegionId': 1 },
                    { 'Id': 2, 'Name': 'Linkou', 'RegionId': 1 },
                    { 'Id': 3, 'Name': 'Tainan', 'RegionId': 2 },
                    {'Id': 4,'Name': 'Kaohsiung','RegionId': 2}];

                $scope.$watch("Region", function (newValue, oldValue) {
                    if (newValue != null && newValue != {}) {
                        $scope.filterCities($scope.Region.Id);
                    }
                });

                $scope.ChangeCity = function () {
                    $scope.selectcity = $scope.City;
                };

            }
        }
    })

Here are the tips,
ü   $watch scope.Region which is two-way-binding from the “Region” drop-down-list.
ü   Set the value of $scope.MyCity, which is two-way binding as well. We will use this ngModel in the next directive.




▋Companies

l   HTML

<my-company selectcity="MyCity">


l   JS

app.directive('myCompany', function () {
        return {
            //restrict: "A",
            scope: {
                selectcity: "="
            },
            template: "<span>{{companies}}</span>",
            link: function ($scope, $element) {
                $scope.$watch("selectcity", function (newValue, oldValue) {
                    if (newValue != null && newValue != {}) {
                        var companies = "";
                        switch ($scope.selectcity.Name) {
                            case "Taipei":
                                companies = "China-trust bank, SYSTEX, Wahlee ...";
                                break;
                            case "Linkou":
                                companies = "Inotera memories ...";
                                break;
                            case "Tainan":
                                companies = "TSMC, Chimei ...";
                                break;
                            case "Kaohsiung":
                                companies = "Foxconn ...";
                                break;
                        }

                        $scope.companies = companies;
                    }
                });
            }
        }
    })