Saturday, November 1, 2014

Angular Ajax Combobox

Angular Ajax Combobox component

Features:
  • On-demand loading of list
  • Paged list
  • Can use page up / page down shortcut when navigating the list
  • Can type on textbox anytime even when the dropdown list is displayed
  • Can use mouse scroll on the popup list
  • Uses AngularJS 1.3 ng-model debounce functionality to prevent fast typist from overwhelming the network
  • Keyboard shortcut to popup the list uses the conventional shortcut, Alt+Down, or F4
  • Aside from next page / previous page buttons, it has fast forward and fast reverse button, it partition the list by 100 instead of the usual ten for paging. Say we have 5,000 rows, a total of 500 pages, so from first page when we click the fast forward button it brings us to page 51
  • Can manually assign both ID/Code and Text for the combobox, by using ng-model and user-input attributes respectively. Think edit
  • When pressing escape key, it reverts back the old value. Likewise when pressing tab, yet the user didn't select an item, the combobox will revert to old ID/Code and Text values
  • Developer still has control on the requested ajax url's parameter names, and also with the result's list and total's property names. The component doesn't impose any names for the ajax's url parameter names and response property names
  • ng-change event, things like cascading combobox is possible
  • Combobox width can be overriden
  • The popup's width has the same width as the combobox
  • Uses bootstrap for the design
  • No jQuery
  • Page Size


Front-end code:
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
 
    <script src="Scripts/angular.min.js"></script>
    <script src="Scripts/angular-resource.min.js"></script>
 
    <link rel="stylesheet" href="Content/bootstrap.min.css" />
 
    <link rel="stylesheet" href="Content/kel.ui.css" />
    <script src="Scripts/kel.ui.js"></script>
 
    <script src="Scripts/app.js"></script>
 
 
</head>
<body ng-app="TheApp" ng-controller="TheController as c">
 
 
    <h3>Angular Ajax Combobox Demo</h3>
 
 
    <div>PersonId chosen: {{c.personId}}</div>
    <br />
    <div style="float: left">Person name:&nbsp;</div>
    <kel-ajax-combobox ng-model="c.personId"
                       user-input="c.personName"
                       result-getter="c.resultGetter"
                       result-list="c.resultList"
                       result-total-rows="c.resultTotalRows"
                       selected-value="'id'"
                       selected-text="'fullName'"
         <!--width="'450px'"-->
         <!--page-size="20"-->
    ></kel-ajax-combobox>
 
</body>
</html>
Output:
app.js:
var app = angular.module('TheApp', ['ngResource', 'kel.ui']);


app.controller('TheController', ['$http', '$resource', function($http, $resource) {
    var vm = this;

    vm.personId = 5500;
    vm.personName = 'Aaron Butler';

    vm.resultList = [];
    vm.resultTotalRows = 0;

    var dataRest = $resource('http://localhost:63692/api/AdventureWorksPeople');

    vm.resultGetter = function(e) {      
         return dataRest.get({ userInput : e.userInput, pageNumber : e.pageNumber, pageSize : e.pageSize }, function(result) {
             vm.resultList = result.persons;
             vm.resultTotalRows = result.totalRows;
         });
    };

    //// This now works:

    //vm.resultGetter = function(e) {
    //        return dataRest.get({ userInput : e.userInput, pageNumber : e.pageNumber, pageSize : e.pageSize }).$promise.then(function(result) {
    //            vm.resultList = result.persons;
    //            vm.resultTotalRows = result.totalRows;
    //        });
    //};

}]);


Sample application layer code:

using System.Web.Http;

using Dapper;

using System.Web.Http;
using System.Collections.Generic;

using ReadyAspNetWebApiCors.Dtos;


namespace ReadyAspNetWebApiCors.Controllers
{
    
    [System.Web.Http.Cors.EnableCors(origins: "*", headers: "*", methods: "*")]
    public class AdventureWorksPeopleController : ApiController
    {
        // GET api/<controller>
        public PagedDtoResult Get([FromUri] PagingDto dto)
        {
            int pageLimit = 10;

            using (var con = new System.Data.SqlClient.SqlConnection(
                                 "Server=.; Database=AdventureWorks2012; Trusted_Connection=true;"))
            {
                var persons = con.Query<PersonDto>(
                    @"with x as (
                        select Id = BusinessEntityId, FullName = FirstName + ' ' + LastName 
                        from Person.Person 
                    )
                    select * 
                    from x
                    where FullName like @filterName + '%' or @filterName = ''
                    order by FullName 
                    offset @offset rows fetch next @pageSize rows only", 
                        new { filterName = dto.UserInput ?? "", 
                              offset = pageLimit * (dto.PageNumber-1), pageSize = dto.PageSize });


                var totalRows = con.ExecuteScalar<int>(
                    @"with x as (
                        select FullName = FirstName + ' ' + LastName 
                        from Person.Person 
                    )
                    select count(*)
                    from x
                    where FullName like @filterName + '%' or @filterName = ''", 
                        new { filterName = dto.UserInput ?? "" });


                return new PagedDtoResult
                {
                    Persons   = persons,
                    TotalRows = totalRows
                    
                };
            }
        }
    
    }
}




namespace ReadyAspNetWebApiCors.Dtos
{
    public class PersonDto
    {
        public int    Id        { get; set; }
        public string FullName  { get; set; }
    }
}

namespace ReadyAspNetWebApiCors.Dtos
{
    public class PagingDto
    {
        public string UserInput { get; set; }        
        public int    PageNumber { get; set; }
        public int    PageSize   { get; set; }
    }
}   





namespace ReadyAspNetWebApiCors.Dtos
{
    public class PagedDtoResult
    {
        public int TotalRows { get; set; }
        public IEnumerable<PersonDto> Persons { get; set; }
    }
}



// Add this on WebApiConfig.Register

config.EnableCors();


var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.Formatting = Newtonsoft.Json.Formatting.Indented;
settings.ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();



Download the library from: http://www.nuget.org/packages/kel.angular.ajax.combobox/

Git: https://github.com/MichaelBuen/AngularAjaxComboBox


Happy Coding!

Thursday, October 30, 2014

AngularJS: Confusing and non-symmetrical callback when using expression binding

There are three ways to communicate values between the directive and the controller


  • For one way string binding, we can use the '@' character
  • For more binding flexibility, we can use bi-directional binding by using the '=' character
  • And then for expression binding, we can use the '&' character



There are two ways to do a callback on Angular, one is to use bi-directional binding, another way is to use expression binding. Expression binding is the recommended way to do a callback, however I find it confusing on some scenario



Here's the complete code:
<div ng-controller="TheController">
  
    <sample-directive the-callback="informParent(theParam)">
        Nice
    </sample-directive>
    
    Received Value: {{valueReceivedFromDirective}}
    
</div>


var theApp = angular.module('theApp',[]);


theApp.directive('sampleDirective', function() {
    return {
        restrict: 'E',
        transclude: true,
        scope : {
            theCallback : '&'
        },
        template: 
        '<div>' + 
            '<div ng-transclude></div>' + 
            '<hr/>' +
            '<div>Comments: <input ng-model="comments" ng-init="comments=\'Great\'"/></div>' +            
            '<div><button ng-click="theCallback({theParam: comments})">Click</button></div>' + 
        '</div>'
    };
});


theApp.controller('TheController', ['$scope', function($scope) {

    $scope.valueReceivedFromDirective = '';
    
    
    // If in case we need to reference a controller's property with same name as directive's parameter 
    // in the callback, there's no way to reference that controller's property. 
    // That is, this can't be referenced in the-callback
    $scope.theParam = 'Blah'; 
    
    // The name must be different from the directive's parameter name:
    $scope.theParamX = 'Meh'; // this can now be referenced in the directive's callback
    
    
    $scope.informParent = function(valuePassed) {    
        // code below is symmetrical to the directive's callback. however, it won't work
        // $scope.valueFromDirective = valuePassed.theParam; 
        
        // so should use this:
        $scope.valueReceivedFromDirective = valuePassed;
    };
    
}]);


Live code: http://jsfiddle.net/jrxh3w1p/1/


As we can see on line 16, we passed an object to the callback parameter, however when it's received on parent callback (line 38), the value received is not the whole object, the parent callback only receives the object's property, hence there's no need to access it as valuePassed.theParam (line 41). The symmetry is broken here

Another oddity, on line 16 it's confusing what property the theParam name is referring to, is it from the directive, or is it from the controller? It could be from the controller, as long as the name doesn't conflict from the directive's parameter name; in our example above, informParent's theParam name is referring to directive instead since the directive has theParam name in its parameter theCallback({theParam: comments}). Try to change line 3 of the HTML, to informParent(theParamX), check it here: http://jsfiddle.net/k4qtL7ez/2/. With expression binding (line 3 of HTML), we cannot ascertain on which property is the parameter in the callback is referring to unless we see the code of the directive; callback by means of expression binding makes the code confusing to read


Another oddity is we cannot pass the comments directly, see: http://jsfiddle.net/tq7pLj8x/1/. Rule is, when using expression binding (uses '&'), the parameter(s) from the directive passed to to the parent's callback must be enclosed in an object. And in parent's callback, the value received is the object's property, not the object itself




If we want to make things more symmetrical, we can use the bi-directional binding by using the '=' sign. Here are the changes:

<div ng-controller="TheController">
  
    <sample-directive the-callback="informParent">
        Nice
    </sample-directive>
    
    Received Value: {{valueReceivedFromDirective}}
    
</div>


var theApp = angular.module('theApp',[]);


theApp.directive('sampleDirective', function() {
    return {
        restrict: 'E',
        transclude: true,
        scope : {
            theCallback : '='
        },
        template: 
        '<div>' + 
            '<div ng-transclude></div>' + 
            '<hr/>' +
            '<div>Comments: <input ng-model="comments" ng-init="comments=\'Great\'"/></div>' +            
            '<div><button ng-click="theCallback({theParam: comments})">Click</button></div>' + 
        '</div>'
    };
});


theApp.controller('TheController', ['$scope', function($scope) {
    $scope.name = 'Superhero';
    
    $scope.valueReceivedFromDirective = '';
    
    $scope.informParent = function(valuePassed) {    
    
        // the parameter passed to this function is now symmetrical how the directive call this function.
        // The directive passed an object to this function, this function received an object too:
        $scope.valueReceivedFromDirective = valuePassed.theParam;
    };
    
}]);

Live code: http://jsfiddle.net/vhx4huk2/


The changes in HTML (line 3) is we didn't call the function directly, we just passed the reference of the controller's method to the directive's property binding (the '=' sign, line #9). With property binding, if we passed an object from the directive's callback (line 16), the parent callback receives an object too (line 31); so if we passed an scalar value from the directive, the parent callback receives scalar value too. See: http://jsfiddle.net/vhx4huk2/1/



If there are no cons against callback using the property binding approach (using '='), it's a lot better than expression binding (using '&'). With property binding approach, there will be no confusion on which property the callback (we only pass the object's method reference) since there is no parameter being passed to it (line 3 of HTML). Another advantage is the caller and callee relationship is very symmetrical, caller passed an object or scalar, the callee receives the same parameter format



Happy Coding!

Sunday, October 12, 2014

Changes to model done outside of AngularJS' callback doesn't reflect on UI

Callbacks made outside of AngularJS can't be monitored by AngularJS, hence when there are changes on model it will not take effect on UI. An example:
<div ng-app='theApp' ng-controller='SampleController as c'>
    
    <label>Search</label><p><input type='text' ng-model='c.topic'/>    
    
    <button ng-click='c.getTopMatch()'>Get Top Match</button>
    
    <p>
        <span ng-show='c.topMatch.length !=""'>Top Match: {{c.topMatch}}<span> 
    </p>
        
</div>


var app = angular.module('theApp', ['oitozero.ngSweetAlert']);

app.controller('SampleController',['$http', 'SweetAlert', function($http, SweetAlert) {
    var self = this;
    
    self.topic = 'angularjs';

    self.topMatch = '';

    
    self.getTopMatch = function() {
                        
        $http.jsonp('http://ajax.googleapis.com/ajax/services/search/web?v=1.0&callback=JSON_CALLBACK',
                    {
                        params : { 'q' : self.topic }
                    })
        .success(function(data) {        

            self.topMatch = data.responseData.results[0].url;  
            
            SweetAlert.swal({
               title: "Clear Search?",
               text: "Everyone wants a clear textbox",
               type: "success",
               showCancelButton: true,
                cancelButtonText: 'No',
               confirmButtonText: "Yes!"
            }, 
            function(isConfirm){                        
     
                if (!isConfirm) return;
                  
                self.topic = '';
                
                
            });      
            
        });     
        
    };
}]);


We can solve that by wrapping our changes on model inside of AngularJS $q service:
var app = angular.module('theApp', ['oitozero.ngSweetAlert']);

app.controller('SampleController',['$http', '$q', 'SweetAlert', function($http, $q, SweetAlert) {
    var self = this;
    
    self.topic = 'angularjs';

    self.topMatch = '';

    
    self.getTopMatch = function() {
                        
        $http.jsonp('http://ajax.googleapis.com/ajax/services/search/web?v=1.0&callback=JSON_CALLBACK',
                    {
                        params : { 'q' : self.topic }
                    })
        .success(function(data) {        

            self.topMatch = data.responseData.results[0].url;  
            
            SweetAlert.swal({
               title: "Clear Search?",
               text: "Everyone wants a clear textbox",
               type: "success",
               showCancelButton: true,
               cancelButtonText: 'No',
               confirmButtonText: "Yes!"
            }, 
            function(isConfirm){                        

                if (!isConfirm) return;                

                var deferred = $q.defer();
                deferred.promise.then(function() {
                    self.topic = '';
                });
                
                deferred.resolve();
                
            });      
            
        });     
        
    };
}]);


Note that we need to inject $q service to our controller. If that's a bit overkill, we can skip the use of $q service and use another approach. Another approach is to dynamically add a promise on existing $http's promise when a callback outside of AngularJS is made, an example:

var app = angular.module('theApp', ['oitozero.ngSweetAlert']);

app.controller('SampleController',['$http', 'SweetAlert', function($http, SweetAlert) {
    var self = this;
    
    self.topic = 'angularjs';

    self.topMatch = '';

    
    self.getTopMatch = function() {
                        
        var thePromise = 
            $http.jsonp('http://ajax.googleapis.com/ajax/services/search/web?v=1.0&callback=JSON_CALLBACK',
                    {
                        params : { 'q' : self.topic }
                    })
            .success(function(data) {        
    
                self.topMatch = data.responseData.results[0].url;  
                
                SweetAlert.swal({
                   title: "Clear Search?",
                   text: "Everyone wants a clear textbox",
                   type: "success",
                   showCancelButton: true,
                    cancelButtonText: 'No',
                   confirmButtonText: "Yes!"
                }, 
                function(){                                        
                    
                    thePromise.then(function() {
                        self.topic = '';
                    });                                
                    
                });      
                
            });     
        
    };
}]);


UPDATE


Another good approach is to use $timeout, unlike $scope.$apply/$scope.$digest, $timeout is testable. Though it works, it is not advisable to use $scope.$apply/$scope.$digest in a controller. $timeout works and it is testable:

var app = angular.module('theApp', ['oitozero.ngSweetAlert']);

app.controller('SampleController',['$http', '$timeout', 'SweetAlert', function($http, $timeout, SweetAlert) {
    var self = this;
    
    self.topic = 'angularjs';

    self.topMatch = '';

    
    self.getTopMatch = function() {
                        
        $http.jsonp('http://ajax.googleapis.com/ajax/services/search/web?v=1.0&callback=JSON_CALLBACK',
                    {
                        params : { 'q' : self.topic }
                    })
        .success(function(data) {        

            self.topMatch = data.responseData.results[0].url;  
            
            SweetAlert.swal({
               title: "Clear Search?",
               text: "Everyone wants a clear textbox",
               type: "success",
               showCancelButton: true,
                cancelButtonText: 'No',
               confirmButtonText: "Yes!"
            }, 
            function(isConfirm){                        

                if (!isConfirm) return;
                
                $timeout(function() {
                    self.topic = '';
                });
                
            });      
            
        });     
        
    };
}]);


Happy Coding!

Thursday, October 9, 2014

AngularJS Get Its POJO Back

Earlier AngularJS version (e.g., 0.9) has no $scope:

function GreetingCtrl(){
    this.greeting = 'Hello';
    this.name = 'Michael';
}    

<div ng:controller='GreetingCtrl'>
      <p>{{greeting}} {{name}}</p>
</div>    

Live example: http://jsfiddle.net/ywuwwgu5/


That's one of the things I find elegant when AngularJS was in its infancy. Aside from there's no special class to inherit from, there is no specialized object(e.g., $scope) the framework need to use in order to do model-binding, just a POJO would bind fine

So on later version of AngularJS when $scope was introduced, it felt like, 'oh, my javascript code would be tied to AngularJS!' I'm thinking why the newer AngularJS version can't do the good old magic where the older framework can bind directly to object's properties, to a POJO


Though porting the code to other javascript MV* frameworks it is not the main overriding concern developers has to face when deciding to use AngularJS or not, there's still a value in making a framework able to work with generic code as much as possible. If there's another javascirpt MV* framework that can bind directly to a POJO like the code above, we can just plug that framework to our generic javascript code and we don't have to rewrite a single line of code.

Code portability feels empowering, just like it feel empowering that your SQL knowledge(or at least a subset of) on one RDBMS is transferable to another RDBMS with little to no rewrite. Unlike with using specialized object like $scope, it feels $scope has many moving parts in it and code portability is just a pipe dream, your code is forever tied to AngularJS; nothing wrong with a code associated to high-quality framework like AngularJS, but still



Now that there is Controller as syntax, we could make our javascript code as generic as possible(and portable), again, yay!

With exactly the same generic AngularJS 0.9 controller code above, we can now re-use it on AngularJS 1.2 using Controller as syntax. We just have to adjust our view, we need to prefix the controller's alias on models we wanted to bind to. Neat!
<div ng-controller='GreetingCtrl as g'>
    <p>{{g.greeting}} {{g.name}}</p>
</div>    


Live code: http://jsfiddle.net/x8mwtox9/


A nice insight so AngularJS 1.2's Controller as won't feel too magical, in AngularJS 1.1 we can also use the this approach of AngularJS 1.2 controller above (albeit without the Controller as syntax) and it would still work. AngularJS 1.1 has no Controller as, but we can achieve the AngularJS 1.2 this code and view just by assigning this on a variable in $scope object:
function GreetingCtrl($scope){
    $scope.g = this;
    this.greeting = 'Hello';
    this.name = 'Michael';
}    

<div ng-controller='GreetingCtrl'>
   <p>{{g.greeting}} {{g.name}}</p>
</div>       

Live code: http://jsfiddle.net/hqfhutLo/


With AngularJS 1.2's Controller as feature, aside from it removes the need of assigning this to $scope manually, we don't have to use specialized object such as $scope anymore. Very generic code, neat! :-)



Happy Coding!

Sunday, October 5, 2014

Use citext on PostgreSQL

Case-insensitive text type is not installed by defaut on Postgres, to use, run this in pgAdmin:

CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public;

Wednesday, October 1, 2014

404 when accessing a subdirectory from nginx

I deployed an ASP.NET MVC application on Ubuntu + nginx + fastcgi-mono-server4, this works:

http://www.example.com/


However this doesn't:

http://www.example.com/Companies/Search?q=softwaremint


The fix is apparently simple, instead of letting nginx manage the subdirectories, let ASP.NET MVC manage it by removing the following (configuration is in /etc/nginx/sites-available/default) :

try_files $uri $uri/ =404;

Failed reloading nginx configuration nginx

michael@buen:/etc/init.d$ sudo nginx -t &&  service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
 * Reloading nginx configuration nginx                                   [fail]
michael@buen:/etc/init.d$ sudo nginx -t && sudo service nginx reload
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
 * Reloading nginx configuration nginx                                   [ OK ]

Put sudo on service too

Saturday, September 27, 2014

Nested route and folder in Laravel

Nested route and folder in Laravel

First approach:

You have this existing route..

Route::get('/Home/{identifikation?}', 'HomeController@showWelcome');

..and you have this existing code organization:

/controllers
    /HomeController.php


And this home controller:

<?php

class HomeController extends BaseController
{

    public function showWelcome($identifikation = null)
    {
        $p = new Person; // this Person class is residing in the folder: /models
        $p->firstname = 'Michael Angelo ' . $identifikation;
        $p->lastname = 'Buen';
        $p->nick = 'Kel';



        // 'Home/ShowWelcome' resolves to /views/Home/ShowWelcome.blade.php
        return View::make('Home/ShowWelcome')->with('ninjaTurtle', $p);

    }

}



However, you have a need to move the Home url under Admin..

Route::get('/Admin/Home/{identifikation?}', 'HomeController@showWelcome');

..and likewise you wanted to move HomeController under Admin folder so the new url maps symmetrically to your code organization:

/controllers 
    /Admin
        /HomeController.php


After moving HomeController under /controllers/Admin folder, go to command-line and run:
composer dump-autoload


Then re-launch your web server:
php artisan serve


That's it! With Laravel, you can route url that maps symmetrically to your code organization. Whereas in ASP.NET MVC, controllers are just limited in these two places: the Controllers and Areas/AreaNameHere/Controllers folders, the controller's folder can't be nested. I digress


However, every time you need to move your controller to another folder, you have to do the composer dump-autoload command-line ritual in order for Laravel to find your controller. Failing to do so, you'll always receive the error "Whoops, looks like something went wrong."



Second approach:

To avoid the composer dump-autoload ritual, we can do it in another way. We'll use PHP's namespace. With the following code organization..
/controllers 
    /Admin
        /HomeController.php

..we'll have to change the routing as followed, we prefix the Admin\ namespace to HomeController class:
Route::get('/Admin/Home/{identifikation?}', 'Admin\HomeController@showWelcome');


..,then just add namespace Admin to HomeController.php:
<?php


namespace Admin;

class HomeController extends \BaseController
{

    public function showWelcome($identifikation = null)
    {
        $p = new \Person;
        $p->firstname = 'Michael Angelo ' . $identifikation;
        $p->lastname = 'Buen';
        $p->nick = 'Kel';

        // 'Home/ShowWelcome' resolves to /views/Home/ShowWelcome.blade.php
        return \View::make('Home/ShowWelcome')->with('ninjaTurtle', $p);

    }

}


As you noticed we have to prefix backslash character on the classes; failing to do so, PHP (not Laravel) will look for BaseController, Person and View classes under the namespace of Admin. To make PHP look for those three classes under the global namespace, we have to prefix those classes with backslash. As we might have to use those classes multiple times, a better approach is to import those classes using the keyword use so we don't have to prefix backslash on all classes:


<?php


namespace Admin;

use BaseController, Person, View;

class HomeController extends BaseController
{

    public function showWelcome($identifikation = null)
    {
        $p = new Person;
        $p->firstname = 'Michael Angelo ' . $identifikation;
        $p->lastname = 'Buen';
        $p->nick = 'Kel';



        // 'Home/ShowWelcome' resolves to /views/Home/ShowWelcome.blade.php
        return View::make('Home/ShowWelcome')->with('ninjaTurtle', $p);

    }

}


You might think, maybe we can just do "use \;", unfortunately PHP doesn't work that way, it doesn't work like C#'s using functionality


On a side note, it's unfortunate that PHP need to use "\" character for namespace delimiter as the dot character is used for string concatenation, otherwise the controller will not look like a folder:

Route::get('/Admin/Home/{identifikation?}', 'Admin.HomeController@showWelcome');


Anyway, when we use namespace, Laravel enforces the controller's code organization to mimic the namespace structure. The HomeController must be moved under the Admin folder. At least in Windows the backslash resembles the code organization :-)

Route::get('/Admin/Home/{identifikation?}', 'Admin\HomeController@showWelcome');



Happy Coding!

Friday, September 26, 2014

Content-heavy sites, choosing between Ruby-on-Rails and PHP

"Easy training, hard battle. Hard training, easy battle!" -- http://www.leonardteo.com/2012/07/ruby-on-rails-vs-php-the-good-the-bad/


While reading Leonard Teo's article on when to choose Ruby-on-Rails or PHP, reading the first few paragraphs I wanted to learn RoR, then on next few paragraphs I'm leaning towards to learn PHP again, then on the middle paragraphs it seems like learning RoR is a wiser choice, but then on the last few paragraphs it felt to me PHP is not that bad; and then when while reading the comments, I'm gravitating again towards RoR, oh well.. :-) It took some six swings when choosing between RoR vs PHP while reading the article up to the last comment


Can't blame me :-) The article was written in 2012 and then updated this year and there are many insightful comments on that article too, having read the entire article and comments, it looks like there is now a renaissance on PHP. There are now new PHP frameworks which doesn't carry the crufts of the older PHP versions and only the language's latest capabilities are applied to new frameworks, making those newer frameworks cleaner and developer-friendly. A PHP MVC framework like Laravel is such an example



I tweeted:

RoR is a mature framework now, it's boring: http://www.leonardteo.com/2012/07/ruby-on-rails-vs-php-the-good-the-bad/

RT @nguerrera Great code is often boring. Exciting code is often wrong.



While RoR is mature now, I'm gravitating towards Laravel; not because it is exciting, but that helps too :-) I used PHP for about half a year on my first job a long time ago, so I'm new to PHP MVC frameworks now. The insightful thoughts from Pierre sealed the deal for me:

As others have suggested here you really should look at Laravel. The frameworks you mention (with the exception o possibly symphony) are what I would call "legacy" frameworks. They all have a long history going back to PHP 4 and are burdened by that legacy.

Laravel lacks that. The author of the framework was not a PHP developer originally. He came from a .NET/Ruby background and arrived on the scene only a few years ago. As such he started by supporting php 5.3 and didn't bother with legacy support.

So Laravel has some of the best features from Rails and .NET baked in: ORM, Active Records, robust routing, generators, migrations, BLADE (think Razor in .NET) etc.... In addition serious PHP frameworks now use Composer for all their components and most of their core. Just like Ruby Gems and Node's packages everything is centralized and not coupled to a particular framework. So you're only updating components via composer using the command line and not your entire framework. (Symphony is using this method as well)

In short, PHP has grown up in some respects. Laravel really is the closest thing PHP has to Rails, if you want to compare something closer in scope have a look at it.



With the author of Laravel experience in ASP.NET MVC, I'm curious to learn how much of the good ideas in ASP.NET MVC are injected into Laravel


So why not just adopt ASP.NET MVC for content-heavy sites since I have experience with ASP.NET MVC too? PHP is ubiquitous, cloud choices is definitely a plus. Microsoft having decided Windows on Azure should carry a premium price tag, Linux on Azure is budget-friendly



As compared to Ruby-on-Rails, Laravel has the controllers done right. See: http://lostechies.com/derickbailey/2014/01/30/playing-with-laravel-4-the-php-mvc-framework-and-telerik-ui/



And how about Java MVC frameworks? You can forgot Java when your server's resources is limited



Happy Coding!

AngularJS bind once musing

After reading this: http://angular-tips.com/blog/2013/08/removing-the-unneeded-watches/


I'm somehow convinced it's better to do the localization during logon only. So bindings on localizations on labels, titles, etc could be done once only


Other good sources on keeping the quantity of $watches low:
http://angular-tips.com/blog/2013/08/watch-how-the-apply-runs-a-digest/
http://www.benlesh.com/2013/10/title.html

Tuesday, September 9, 2014

Thoughts On Best Practices

OH: “Do programmers have any specific superstitions?”

“Yeah, but we call them best practices.”

-- David Grandinetti




Good read on best practices:

"It has a chilling effect on our progress as an intellectual craft when people pretend that a best practice exists" -- James Bach

"Rather than simply stating what we've done and how we did it, we feel compelled to puff it up into a spiny, intimidating best practice. We attach our egos to our code frameworks. If someone doesn't agree with our approach, they're attacking us personally. If someone has a different best practice, they're amateurs who don't understand the problem domain" -- Jeff Atwood




My aversion on best practices, everyone has their own beliefs, it follows that everyone has their own notion of best practice


There's really no one best practice, everyone has one; or should we just take it the easy way and just find like-minded folks who share our notion of best practice? It's not good to find folks who'll just reinforce same beliefs, things are a lot better and interesting when we find others who can find loopholes or provide constructive criticism on things we believe are right



Lastly, most of the time, I find that people who tend to ask a best practice question can be classified in two types, either they are lazy and wanted to be spoonfed or an askhole



Believing our practice is the best practice, tends to make us crap on other people's choice and enthusiasm, and it's not good



Better not to believe there's a best practice at all especially if we will just use it on intimidating other people



Happy Coding!

Thursday, August 21, 2014

When using jQuery, let its API do the heavy lifting

Instead of this:

var particles = $('.particle');
$('li').each(function() {
    if (!$(this).is(particles))
        $(this).css('color','red');
});    



Do this:
var particles = $('.particle');
$('li').not(particles).css('color','red')

Thursday, July 24, 2014

On TypeScript, the this keyword doesn't always reference the instance of a class

///<reference path='jquery.d.ts' />

class Mate {
    public n : number;

    public name : string = "Freddie";

    public nick : string = "Fred";



    public message() : void {

        var people = new Array<Person>();



        {
            var p = new Person();
            p.name = "Ely";
            people.push(p);
        }

        {
            var p = new Person();
            p.name = "Raymund";
            people.push(p);
        }




        $.each(people, function() {
            alert('inline: ' + this.name + ' -- ' + this.nick);
        });
        /*
        Outputs:
        inline: Ely -- undefined
        inline: Raymund -- undefined
        */


        $.each(people, this.alerter);
        /*
        Coming from traditional OOP, I expected:
        Freddie -- Fred
        Freddie -- Fred

        What happens:
        Ely -- undefined
        Raymund -- undefined
        */



        $.each(people, () => alert('inline: ' + this.name + ' -- ' + this.nick) );
        /*
        Outputs:
        inline: Freddie -- Fred
        inline: Freddie -- Fred
        */


        $.each(people, () => this.alerter());
        /*
        Outputs:
        Freddie -- Fred
        Freddie -- Fred
        */


    }

    public alerter() : void {
        alert(this.name + ' -- ' + this.nick);

    }

}

class Person {
    public name : string;
}


$(function() {
    var m = new Mate();
    m.message();
});

Thursday, May 15, 2014

Tuesday, May 6, 2014

PostgreSQL (mis)feature

Martin Smith pointed out a gotcha on Postgres feature I recommended


GROUP BY on alias doesn't work properly when the alias has a same name from the table's columns

select 'foo' as Table_name
from information_schema.tables 
group by Table_name


Live code: http://sqlfiddle.com/#!15/d41d8/1920

Tuesday, April 22, 2014

Dropdown in ng-grid

The controller:

var app = angular.module('app', ['ngGrid']);

app.controller('bodyController', function($scope, LanguageList) {
  $scope.myData = [{name: "Moroni", language: 'fr'},
                     {name: "Tiancum", language: 'en'},
                     {name: "Enos", language: 'nl'}];
    $scope.gridOptions = {
            data: 'myData',
                enableCellSelection: true,
                enableRowSelection: false,
                enableCellEditOnFocus: true,
            columnDefs: [
                {
                    field: 'language', enableFocusedCellEdit: true,
                    editableCellTemplate: 'language_edit.html',
                    cellFilter : 'LanguageMap'
                },
                {field: 'name', enableFocusedCellEdit: true }

            ],
            canSelectRows: false
        };
        
    $scope.languages = LanguageList;
    
})
.factory('LanguageList', function() {
  return [
      { language_code : 'en', language_title: 'English' },
      { language_code : 'fr', language_title: 'French' },
      { language_code : 'nl', language_title: 'Netherlands' }
      ];
})
.filter('LanguageMap', function(LanguageList) {
  
  return function(input) {
    
    var languagesMatched = LanguageList.filter(function(lang) {
      return lang.language_code == input;
    });
    
    if (languagesMatched.length == 1)
        return languagesMatched[0].language_title;
    else
        return '*unknown language*'
    
    
    return text;
  }
});


Main page
<!DOCTYPE html>
<html ng-app="app">
  
  <head lang="en">
    <meta charset="utf-8">
    <title>Custom Plunker</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    
    <script type="text/javascript" src="ng-grid.js"></script>
    <link rel="stylesheet" href="style.css">
    <link rel="stylesheet" href="ng-grid.css">
    <script>
      document.write('<base href="' + document.location + '" />');
    </script>
    <script src="app.js"></script>
  </head>
  
<body ng-controller="bodyController">
    <div ng-grid="gridOptions" style="height: 400px">
    </div>
    
    
    {{myData}}
</body>

</html>


language_edit.html, dropdown template:
<select 
ng-cell-input 

ng-options='l.language_code as l.language_title for l in languages'

ng-class="'colt' + $index" ng-model="COL_FIELD" ng-input="COL_FIELD" data-placeholder="-- Select One --" 
>


</select>


Live code: http://plnkr.co/edit/IOBXNy2hcJWbtMXZS3SO?p=preview

Friday, March 14, 2014

Sprite Kit: Animation in English-Speak

Message sequence of actions to SKAction, then message that sequence of actions to repeatActionForever, then run that forever action to the player (SKSpriteNode)


Thursday, March 13, 2014

Sprite Kit: Up is down, down is up

There's no error on messaging the location.x to moveToX action of SKAction, think spaceship which just move left and right and remains stationary on its Y


-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch* touched = [touches anyObject];
    

    CGPoint location = [touched locationInView:self.view];

    
    SKAction* moveAction = [SKAction moveToX: location.x duration:0.0];
    
    
    [player runAction: moveAction];
}


However, it's preferable to use locationInNode. If we want the spaceship to move in all direction yet we use locationInView, the app will exhibit this same error: http://stackoverflow.com/questions/21948027/skaction-moveto-goes-up-when-should-go-down

CGPoint location = [touched locationInView:self.view]
SKAction* moveAction = [SKAction moveTo: location duration:0.0];    


Though the spaceship's X will move accordingly to your touch, the spaceship's Y will not follow your finger movements.


To rectify that flaw, get the location from SKScene's view (self) instead of the UIView's view (self.view), then message that view to touched object's locationInNode instead of locationInView


CGPoint location = [touched locationInNode:self];
SKAction* moveAction = [SKAction moveTo: location duration:0.0];



Happy Coding! ツ

Wednesday, March 12, 2014

Sprite Kit: Determine touch location in English-speak

Create a touchesMoved event in the game scene. To determine the touched location, first get a UITouch from touched object (use anyObject), then from that UITouch object get its location(CGPoint) in view, with the parameter being the game scene's view.

To move an object (e.g. player (SKSpriteNode)), message the location(CGPoint) to the moving action functionality (moveTo) of an action(SKAction). Then message that action to the player's (SKSpriteNode) run action functionality

Tuesday, March 11, 2014

Making sense of Sprite Kit and iOS's MVC

Sprite Kit flow in English-speak

From the ViewController’s viewDidLoad we configure the view by doing the following:

1. Create a game view by casting the ViewController’s view to SKView

    SKView has some properties like:

         showsFPS, showsNodeCount, showsDrawCount


2. We create game scene via instance of a class that derives from SKScene

3. Then we call game view’s presentScene to present the game scene


A game scene extends SKScene. On game scene’s initialization: 

1. We can set the size of the scene, from the scene we can also set the background color. 

2. We can add a player (instance of SKSpriteNode) on game scene by calling the game scene’s addChild which has a parameter of SKSpriteNode

Friday, February 28, 2014

NoProgramming

Can we survive the onslaught of frameworks that makes our job easier and could potentially make our jobs obsolete?

First, there's No Software, then there's NoSQL, now No Programming is needed when making an application. Ok I exaggerated a bit, in this stage of technology we can now learn to make applications with almost no programming background required.

You got a complete list (no paging) of data a user wanted to filter, it would be overkill to re-fetch the data from the server as all the data being used on filtering are already at the client-side. We can use some jQuery skills or some good ol' DOM manipulation skills to do that task. But who would do that when the No technologies are all the rage now?

Here's one of the many ways to do no programming with AngularJS, enjoy! Active filtering: http://docs.angularjs.org/api/ng/filter/filter

Programming required to fit the filter requirement of clicking the search button first: almost no programming required http://fiddle.jshell.net/G8z9Q/

Thursday, February 13, 2014

Sparrow Framework newbie: Run is not available on project


Run is not available on Scaffold project:




Switch to Scaffold project:

When DEFAULT doesn't default

I almost gave a wrong code review to a colleague:


It's better to use NOT NULL:

ALTER TABLE dbo.blah
ADD IsTransferred BIT NULL DEFAULT (0);

Is there a business or technical reason why IsTransferred should be nullable?

On the above DDL for IsTransferred, nullable or not nullable, IsTransferred defaults to 0, hence this is a superfluous code:

-- initialize new column, i.e., NULL columns, to "not transferred"
UPDATE dbo.blah
SET IsTransferred = 0
WHERE IsTransferred IS NULL ;


Further read: http://sqlblog.com/blogs/hugo_kornelis/archive/2007/07/06/null-ndash-the-database-rsquo-s-black-hole.aspx

The code could be shortened and optimized but I'm not inclined to advise it; this query is just a one-time thing, no need to micro-optimize. The code is good enough


Spotted the wrong thing on the above advice? The above advice is correct if we are using PostgreSQL. However we are using SQL Server, the newly-added IsTransferred field will default to null if the field is nullable regardless of the above DDL indicating a default value of false(0).


So the UPDATE above is not a superfluous code, at least on SQL Server, the UPDATE is still needed despite the DEFAULT 0 clause. PostgreSQL (and other RDBMSes for that matter) is intuitive in this regard, it honors the DEFAULT clause regardless of the field is nullable or not.


Further read: http://sqlblog.com/blogs/hugo_kornelis/archive/2007/07/06/null-ndash-the-database-rsquo-s-black-hole.aspx


PostgreSQL-related news: https://twitter.com/spolsky/status/433323487961178113



Happy Coding! ツ

Wednesday, January 22, 2014

Mac OS X

If you love your health and time, when you outgrown Linux as your choice of Unix, especially when father time is catching up, opt to use a Unix that cares about your sanity and taste, use Mac OS X


I once needed to compile a WiFi driver (written in C language, C is a first-class assembly language in Unix) for my Ubuntu-toting laptop, it was cool then. In our modern times, the hardware and software are now tightly integrated, who has a time to compile drivers? Think iPad or Surface Pro requiring users to compile drivers for the device's WiFi, users will go batshit insane if they have to endure performing this task.


I still think compiling non-kernel softwares as kinda cool though, on my first work a colleague introduced MySQL to us, we used MySQL we compiled ourselves, no installer, just C source code. It feels so empowering having the source code and knowing that we can introduce functionalities that integrated well to the RDBMS's bare metal.

Wednesday, January 8, 2014

Too many computer jargons in one picture



  • Happy Path
  • Bus Factor
  • Service Bus
  • Bugs
  • Hitting a wall
  • Red Flag
  • Nerdgasm
  • Trailing Space
  • Terminal