Thursday, 15 June 2017

Open Link on Browser in Ionic Framework

To be able to open a link in an Ionic Framework based app, we need to install InAppBrowser plugin. If you use Visual Studio Tools for Apache Cordova, you can open config.xml file and find in Plugins section.

After installing the plugin, we don’t need to pass any new module in the code function constructor. All we need to do is just to call the functions directly like:
cordova.InAppBrowser.open('http://www.google.com', '_system');
// or we can use
window.open('http://www.google.com', '_system');
_system target is used so that the link will be opened on system's web browser.

In HTML code, we can call like this:
<a href="#" onclick="window.open('https://www.google.com', '_system');">my link</a>
Don’t forget to include the ‘http://’ otherwise you will get an error like ‘Cannot display PDF (… cannot be opened).

Thursday, 9 February 2017

Ionic Modal with this Controller

Below is a simple example of using Ionic Modal with this controller (Controller As):
var vm = this;
    . . .
    . . .
    . . .

    /* modal */
    vm.showModal = function () {
        $ionicModal.show();
    };

    $ionicModal.fromTemplateUrl('my-modal.html', {
        scope: $scope,
        animation: 'slide-in-up'
    }).then(function (modal) {
        vm.modal = modal;
    });

    vm.openModal = function () {
        vm.modal.show();
    };

    vm.closeModal = function () {
        vm.modal.hide();
    };

    // Clean up the modal
    $scope.$on('$destroy', function () {
        vm.modal.remove();
    });

    // Execute action on hide modal
    $scope.$on('modal.hidden', function () {
        . . .
    });

    // Execute action on remove modal
    $scope.$on('modal.removed', function () {
        . . .
    });
Note that we still need to use $scope for particular function.

The modal template:
<ion-modal-view>
    <ion-header-bar>
        <h1 class="title">My Modal title</h1>
    </ion-header-bar>
    <ion-content>
        Hello!
        <button ng-click="vm.closeModal()">Close</button>
    </ion-content>
</ion-modal-view>

Tuesday, 8 November 2016

Quick Guide to Use Ionic Framework Side Menu

This post will guide you to quickly set side menu in Ionic Framework.

Firstly, we need to set up the routes in app.js file. In this case we have our menu template in menu.html file. We need to name the menu state (e.g. app) and then all other pages will have states with this syntax menuStateName.pageStateName. We will also need to set abstract: true for the menu state.

Below is an example:
ionicApp.config(['$stateProvider', '$urlRouterProvider',
    function ($stateProvider, $urlRouterProvider) {
        $stateProvider
            .state('app', {
                url: '/app',
                abstract: true,
                templateUrl: 'menu.html'
            })
          .state('app.add', { // add item page
              url: "/add",
              views: {
                  'menuContent': {
                      templateUrl: 'add-item.html'
                  }             
              }
          })
          .state('app.list', { // list items page
              url: "/list",
              views: {
                  'menuContent': {
                      templateUrl: 'list.html'
                  }             
              }
         })
         .state('app.edit', { // edit item page
             url: "/edit/:itemId",
             views: {
                 'menuContent': {
                     templateUrl: 'edit-item.html'
                 }             
             }
         });
        // if none of the above states are matched, use this as the fallback
        $urlRouterProvider.otherwise('/app/add');
    }
]);

On index.html, we just need to put <ion-nav-view></ion-nav-view>.
<body ng-app="ionicApp">
      <ion-nav-view></ion-nav-view>
  </body>

Then on each page file, we have ion-view and ion-content:
<ion-view view-title="PageTitle">
  <ion-content>
    ... your markup content ...
  </ion-content>
</ion-view>

Then on the menu markup file (menu.html), we have something like this:
<ion-side-menus enable-menu-with-back-views="true">
    <ion-side-menu-content>
        <ion-nav-bar class="bar">
            <!--<ion-nav-back-button>
            </ion-nav-back-button>-->
            <ion-nav-buttons side="left">
                <button class="button button-icon ion-navicon" menu-toggle="left"></button>
            </ion-nav-buttons>
        </ion-nav-bar>
        <ion-nav-view name="menuContent"></ion-nav-view>
    </ion-side-menu-content>
    <ion-side-menu side="left">
        <ion-header-bar class="custom-brown">
            <div class="title">Menu Title</div>
        </ion-header-bar>
        <ion-content>
            <ion-list>
                <ion-item menu-close href="#/app/add">
                    <b>Add Item</b>
                </ion-item>
                <ion-item menu-close href="#/app/list">
                    <b>List Items</b>
                </ion-item>
                <ion-item menu-close href=". . .">
                    <b>. . .</b>
                </ion-item>
                <ion-item menu-close href=". . .">
                    <b>. . .</b>
                </ion-item>
            </ion-list>
        </ion-content>
    </ion-side-menu>
</ion-side-menus>
On the example above, I use enable-menu-with-back-views="true" so that the menu icon will always be displayed. I also commented out <ion-nav-back-button></ion-nav-back-button> to hide the back button so only the menu icon will be displayed.

We can also have the menu items populated dynamically. We could use something like below:
                <ion-item menu-close ng-repeat="item in vm.items" ui-sref="app.edit({itemId: {{item.itemId}}})">
                    <b>Edit :</b> {{item.name}}
                </ion-item>

Thursday, 20 October 2016

Setting HTTP Strict Transport Security (HSTS) in ASP.NET Application

Setting HSTS on a website application is one way to avoid Man in the Middle attack which modifies server response to use insecure connection to gain user information.
One online tool that can be used to check whether our website has HSTS or not is https://www.ssllabs.com/ssltest . If on the report, it shows that:
'Strict Transport Security (HSTS) : No'
then it means that it is not set.

To set HSTS in web.config file, add these configurations below inside <system.webServer> node:
<rewrite>
 <rules>
  <rule name="HTTP to HTTPS redirect" stopProcessing="true">
   <match url="(.*)" />
   <conditions>
    <add input="{HTTPS}" pattern="off" ignoreCase="true" />
   </conditions>
   <action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
    redirectType="Permanent" />
  </rule>
 </rules>
 <outboundRules>
  <rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
   <match serverVariable="RESPONSE_Strict_Transport_Security"
    pattern=".*" />
   <conditions>
    <add input="{HTTPS}" pattern="on" ignoreCase="true" />
   </conditions>
   <action type="Rewrite" value="max-age=31536000" />
  </rule>
 </outboundRules>
</rewrite>

However if we do not have URL Rewrite module installed in IIS, we will have a 500 internal server error. This is because IIS does not understand <rewrite> node in the codes.

We can download URL Rewrite module from https://www.iis.net/downloads/microsoft/url-rewrite


References:
http://www.hanselman.com/blog/HowToEnableHTTPStrictTransportSecurityHSTSInIIS7.aspx
http://serverfault.com/questions/417173/enable-http-strict-transport-security-hsts-in-iis-7/629594
https://www.tbs-certificates.co.uk/FAQ/en/hsts-iis.html
https://www.iis.net/learn/extensions/url-rewrite-module/creating-rewrite-rules-for-the-url-rewrite-module

Monday, 19 September 2016

Directive to Parse and Format Number from and to Currency

This post will show an example of an AngularJS directive that will automatically format a plain number inserted into an input field into a currency format. As the number is typed into the input field, the value will be formatted into its local currency representation. The directive also converts a number value from model to its currency format in the view.
$formatters, $parsers and $filter are used as part of the codes.
myApp.directive('formatCurrency', ['$filter', '$locale', function ($filter, $locale) {
    return {
        require: '?ngModel',
        link: function (scope, elem, attrs, ctrl) {
            if (!ctrl) return;

            // $formatters is used to process value from code to view
            ctrl.$formatters.unshift(function (modelValue) {
                var formattedValue;
                if (modelValue) {
                    formattedValue = $filter('currency', null, 2)(modelValue);  // use $filter to do some formatting
                } else {
                    formattedValue = '';
                }
                return formattedValue;
            });

            // $parsers is used to process value from view to code
            ctrl.$parsers.unshift(function (viewValue) {
                var plainNumber;
                var formattedValue;
                
                var decimalSeparatorIndex = viewValue.lastIndexOf($locale.NUMBER_FORMATS.DECIMAL_SEP);  // $locale.NUMBER_FORMATS.DECIMAL_SEP variable is the decimal separator for the current culture
                if (decimalSeparatorIndex > 0) {
                    // if input has decimal part
                    var wholeNumberPart = viewValue.substring(0, decimalSeparatorIndex);
                    var decimalPart = viewValue.substr(decimalSeparatorIndex + 1, 2);
                    plainNumber = parseFloat(wholeNumberPart.replace(/[^\d]/g, '') + '.' + decimalPart).toFixed(2); // remove any non number characters and round to two decimal places

                    formattedValue = $filter('currency', null, 2)(plainNumber);
                    formattedValue = formattedValue.substring(0, formattedValue.lastIndexOf($locale.NUMBER_FORMATS.DECIMAL_SEP) + 1);
                    formattedValue = formattedValue + decimalPart;
                } else {
                    // input does not have decimal part
                    plainNumber = parseFloat(viewValue.replace(/[^\d]/g, ''));
                    formattedValue = $filter('currency', null, 0)(plainNumber);     // the 0 argument for no decimal does not work (issue with Angular)

                    if (formattedValue) {
                        // remove the decimal part
                        formattedValue = formattedValue.substring(0, formattedValue.lastIndexOf($locale.NUMBER_FORMATS.DECIMAL_SEP));
                    } else {
                        formattedValue = viewValue;
                    }
                }

                elem.val(formattedValue);
                return plainNumber;
            });
        }
    };
}]);

To use it on an input field:
<input type="text" ng-model="vm.myVariable" format-currency/>

For a working example, please see this on Plunker.

Friday, 2 September 2016

Passing Controller Function to Directive

Below is an example of how to call a controller function from inside an AngularJS directive:
myApp.directive('myDirective', function () {
    return {
        scope: { controllerFunction: '&callbackFunction' },
        link: function (scope, element, attrs) {
            scope.controllerFunction({ arg: '123' });
        },
    }
});
And the markup:
<div ng-controller="MyCtrl as vm">
      <span my-directive callback-function="vm.theControllerFunction(arg)" ></span>
</div>

We can also call the controller function whenever a value in the directive changes. An example of such directive:
myApp.directive('observeValueChange', function () {
    return {
        scope: { controllerFunction: '&callbackFunction' },
        link: function (scope, element, attrs, ngModel) {
            attrs.$observe('theValue', function (newValue) {
                scope.controllerFunction({ arg: newValue });
            })
        },
    }
});
The markup:
<input type="text" ng-model="vm.myVariable" />
      <span observe-value-change the-value="{{vm.myVariable}}" callback-function="vm.theControllerFunction(arg)" ></span>

See the working example in Plunker.

Thursday, 11 August 2016

Some Notes about SQL Index Fragmentation

This post is about a recent reading/research that I have made regarding of how to identify ‘bad’ indexes that have been defragmented much and how to fix those to be optimal again. There are many references put on this post such as useful scripts and articles for further reading.

Identifying Defragmented Indexes
Firstly, we would need to find the indexes that have much fragmentation. Below is a useful script from Microsoft Script Center site. This script shows average fragmentation for each index in all tables and indexed views.
SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName,
ind.name AS IndexName, indexstats.index_type_desc AS IndexType,
indexstats.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) indexstats
INNER JOIN sys.indexes ind 
ON ind.object_id = indexstats.object_id
AND ind.index_id = indexstats.index_id
WHERE indexstats.avg_fragmentation_in_percent > 0--You can specify the percent as you want
ORDER BY indexstats.avg_fragmentation_in_percent DESC

What to Do with the Result?
From the result we can either choose to ignore, reorganise or rebuild each index.

Reorganising an index is to reorder and clean up the index with pre-existing settings. While rebuilding an index is to recreate the index from scratch. When rebuilding an index, new settings can be set as the old index will be deleted. Rebuilding an index is usually more effective than reorganising an index. However rebuilding an index will cost more.

Reorganising an index is always done online while rebuilding is offline (except if using SQL Server Enterprise edition). Stopping a rebuilding operation will make the operation to be rolled back while stopping reorganising operation will just stop the process and leave the done parts.

According to Microsoft guideline, if an index has
- less than 5 % fragmentation -> ignore
- between 5% to 30% fragmentation -> reorganise
- greater than 30 % fragmentation -> rebuild


How to Reorganise / Rebuild Index?
An index can be reorganised or rebuilt with Alter Index command. For example:
ALTER INDEX IX_MyTable_IndexName ON MyTable REORGANIZE;   
ALTER INDEX IX_MyTable_IndexName ON MyTable REBUILD;
To see all options for the command, see this MSDN documentation.


Reorganise / Rebuild all Indexes in the Database
To do this, we can use Maintenance Plan Wizard provided by SQL Server or script.

To create a maintenance plan:
1. expand the Management folder in the target database server
2. right click Maintenance Plans folder and select Maintenance Plan Wizard

For more details about using Maintenance Plan Wizard to rebuild indexes, please see this article 'Rebuilding Indexes using the SSMS Database Maintenance Wizard'.

Otherwise we can use script to reorganise/rebuild indexes. An example of simple script to rebuild all indexes of tables and indexed views in a database (source is http://www.sqlservercentral.com/blogs/juggling_with_sql/2011/06/20/rebuild-all-the-indexes-of-a-sql-database-in-one-go/):
DECLARE @tsql NVARCHAR(MAX) 
DECLARE @fillfactor INT

SET @fillfactor = 90

SELECT @tsql =
STUFF(( SELECT DISTINCT
';' + 'ALTER INDEX ALL ON ' + o.name + ' REBUILD WITH (FILLFACTOR = ' + CONVERT(VARCHAR(3),@fillfactor) + ')'
FROM
sysobjects o
INNER JOIN sysindexes i
ON o.id = i.id
WHERE
o.xtype IN ('U','V')
AND i.name IS NOT NULL
FOR XML PATH('')), 1,1,'')

--PRINT @tsql         
EXEC sp_executesql @tsql

Or we can use more sophisticated script that has been used and proven by many people like Index Defrag Script.


I have Done Rebuilt but the Index Fragmentation is Still High
Fragmentation in an index of a small table may not be reduced even after reorganising or rebuilding because they may be stored on mixed extents that are shared with different objects. We might want to check as well whether by having the index is actually helping to improve query performance or not. If not then this index can be considered to be removed.


References and further reading:
Reorganize and Rebuild Indexes
Rebuild or Reorganize: SQL Server Index Maintenance