Saturday, September 27, 2014

JavaScript !! - bang, bang

The !! construct is a simple way of turning any JavaScript expression into its Boolean equivalent.

legendary Cast-to-bool 'operator',  "bang, bang you're boolean"

Coerces Object to boolean. If it was falsey (e.g. 0, null, undefined, etc.), it will be false, otherwise, true.

!oObject  //Inverted boolean
!!oObject //!! converts the value to the right of it to its equivalent boolean value

true === !!10
false === !!0
So !! is not an operator, it's just the ! operator twice. It is the double-use of ! -- which is the logical "not" operator.
The "falsey" values are:
  • false
  • NaN
  • undefined
  • null
  • "" (empty string)
  • 0

Friday, September 26, 2014

JavaScript Array.prototype:[]

Array.prototype can be shortcut as '[]'
var s= 'caatJavaScript';
var arrayStr_ = Array.prototype.slice.call(s,1);
console.log(arrayStr_);
["a", "a", "t", "J", "a", "v", "a", "S", "c", "r", "I", "p", "t"]  

var arrayStr__ = [].slice.apply(s,[]);//the same as [].slice.apply(s);
console.log(arrayStr__.join(''));
caatJavaScript 

var arrayStr__ = [].slice.call(s,0);//the same as [].slice.call(s);
console.log(arrayStr__.join(''));
caatJavaScript

var arrayStr__ = [].slice.call(s,1);
console.log(arrayStr__);
["a", "a", "t", "J", "a", "v", "a", "S", "c", "r", "i", "p", "t"]
console.log(arrayStr__.join(''));
aatJavaScript 

console.log(arrayStr__.pop());
t 

var arrayStr__ = [].slice.call(s,s.length-1);
console.log(arrayStr__);
["t"] 

Wednesday, September 24, 2014

AngularJS: evaluating when the angular loading done

Here is the code
    DCTApp.directive('caatInitialized',
    ['$rootScope',
        function($rootScope) {
            return {
                restrict: 'A',
                link: function($scope) {
                    var to;
                    var listener = $scope.$watch(function() {
                        clearTimeout(to);
                        to = setTimeout(function () {
                            console.log('detail Initialized');
                            listener();
                            $rootScope.$broadcast('detailInitialized');
                        }, 50);
                    });
                }
            };
        }]);

Listening (I am calculating the height of the Kendo UI Grid Content here)
        $scope.$on('detailInitialized', function () {
            if (typeof _navParam !== 'undefined' && _navParam !== '') {
                $('.sidebar').show();                
            }
            $('#MemberGrid .k-grid-content').height($('.contentDetail').height() - $('#MemberGrid .k-grid-pager').outerHeight() - $('#MemberGrid .k-grid-header').outerHeight());
            
        });

Then add as an attribute to the element monitoring.
And a note from original post:
It works by assuming that the application is initialised when there are no more $digest cycles. $watch is called every digest cycle and so a timer is started (setTimeout not $timeout so a new digest cycle is not triggered). If a digest cycle does not occur within the timeout then the application is assumed to have initialised.
It is obviously not as accurate as satchmoruns solution (as it is possible a digest cycle takes longer than the timeout) but my solution doesn't need you to keep track of the modules which makes it that much easier to manage (particularly for larger projects). Anyway, seems to be accurate enough for my requirements. Hope it helps.

HTML5 History API: update URL location

push state to update the URL (with Kendo UI Grid state change):
        $('#MemberGrid').on('click', " tbody > tr", function () {//delegate("tbody > tr", "click", function(){//prior to jQuery 1.7
            var $grid = $("#MemberGrid").data("kendoGrid");
            var data = $grid.dataItem(this);
            var url = location.href;
            var _privateData = $("#XXX").val();
            url = url.replace(_privateData, data.privateData);
            $("#XXX").val(data.privateData);
            $rootScope.$broadcast('detailNav-started');
            //save state as well
            var stateObj = { id: data.privateData };
            window.history.pushState(stateObj, null, url);
        });

And PopState to setup a callback to listen when the “back” or 'forth' button is pressed,(with Kendo UI Grid state change):
window.onpopstate = function(e){
            var url = location.href;
            var privateData_temp = $("#XXX").val();
            var currentState = e.state;
            $("#XXX").val(currentState.id);
            $rootScope.$broadcast('detailNav-started');
            var $grid = $("#MemberGrid").data("kendoGrid");
            $grid.table.find("tr td:last-child").filter(function () { return $.text([this]) == privateData_temp; }).closest('tr').removeClass("k-state-selected");
            $grid.table.find("tr td:last-child").filter(function () { return $.text([this]) == currentState.id; }).closest('tr').addClass("k-state-selected");
        }

Kendo UI Grid: manipulate the loaded grid rows

How To detect when the grid DOM is ready after a refresh? Or, alternatively, is there a way to detect as each TR element is created.

Actually, it can be done in dataBound as below:
(The code is trying to find from the td in the last column then filter it)
            dataBound: function () {
                var grid = this;
                grid.table.find("tr td:last-child").filter(function () { return $.text([this]) == $("#XXX").val(); }).closest('tr').addClass("k-state-selected");
                //save to history state
                var stateObj = { id: $("#XXX").val() };
                window.history.pushState(stateObj, null, null);
                return;
            }
            }

Kendo UI Grid: Send Custom request parameter or replace filter parameter

One day I need to pass the Kendo UI grid filter to server ( The idea is to re-use the filter pre-configured from the original grid for the new grid ). However KendoUI  API does not provide the way for you to override the filter request as obvious as other parameters such as pagesize, schema etc.

There are 2 ways to override the filter for KendoUI grid:

1. add filter param into transport.read.data as below
    $('#MemberGrid').on('dblclick', " tbody > tr", function () {
        var $grid = $("#MemberGrid").data("kendoGrid");
        var data = $grid.dataItem(this);        
        var datasourceFromGrid = $grid.dataSource;        
        $theForm = $("#detailswithNav");

        //..append a hidden input that holds passing val
        $("<input type='hidden' />")
        .attr("name", "myDetailReqParam")
        .val(JSON.stringify(new DetailParamModel(datasourceFromGrid._filter,datasourceFromGrid._page,datasourceFromGrid._pageSize,datasourceFromGrid._sort,datasourceFromGrid._take,datasourceFromGrid._skip,datasourceFromGrid.transport.options.read, datasourceFromGrid.options.schema, data.privateData)))
        .appendTo($theForm);

        $theForm.attr("action", $theForm.attr("action") + "/" + data.privateData).submit();           
        });       
        
        
        });

        function DetailParamModel(_filter,_page,_pageSize,_sort,_take,_skip,_read,_schema,_dataRow){
            var detailParam = this;
            detailParam.page = _page;
            detailParam.pageSize = _pageSize;
            detailParam.sort = _sort;
            detailParam.take = _take;
            detailParam.skip = _skip;
            detailParam.read = _read;
            if( typeof _filter !== 'undefined' )
                detailParam.read.data.filter = _filter;
            detailParam.schema = _schema;
            detailParam.privateData = _dataRow;
        
        }

2. add filter param into options as below:
transport: {
                    type: "json",
                    read: _navParam.read,
                    parameterMap: function (options, type) {
                        if (type === "read") {

                            //Added to options for custom request 
                            options.filter = _navParam.filter;

                            return kendo.stringify(options);
                        }
                    }
                }

Tuesday, September 23, 2014

Uncaught SyntaxError: Unexpected token; ASP.NET MVC razor in javascript

To be sure wrap ASP.NET MVC razor data in quote, otherwise you might get Uncaught SyntaxError: Unexpected token;

The code I had:

(function () {
        try{
            var __navParam = '@navParam';
            if (typeof __navParam === 'undefined' || __navParam === '') _navParam = '';
            else //use Json.parse to convert string to Json
                _navParam = JSON.parse(@Html.Raw(navParam));

            if (typeof _navParam === 'undefined' || _navParam === '') { 
            $('.sidebar').hide();
            $('#detailContent').removeClass('contentDetail');            
        }
        }catch(e) {
            $('.sidebar').hide();
            $('#detailContent').removeClass('contentDetail');       
        }
    })();

I also added this in the razor code for json serialization with json formatted data from ViewData:
    var jss = new System.Web.Script.Serialization.JavaScriptSerializer();
    var strNav = Convert.ToString(ViewData["NavParam"]);
    var navParam = string.IsNullOrEmpty(strNav)? string.Empty : jss.Serialize(strNav);