Underscore.JS: Access local variables and function inside each function of UnderscoreJS in Typescript

Standard

While using AngularJS with Typescript, I witnessed the scenario, where my function is accessing variables and functions defined in controller constructor, to make life easy for some collection manipulation, I used underscoreJS helper functions, _.each

_.each(data, function(item : any) {
     item.name = this.formatName(item);
});

Everything was on track, except I was unable to access local variables and functions(this.formatName) defined in the angular controller in underscoreJS _.each, I was getting an undefined error for this.formatName method inside _.each.

Solution:

As you are aware of the fact that ‘this‘ keyword behaves differently in JavaScript compared to other languages. For Typescript, ‘this‘ keyword refers to the current instance of the class. In JavaScript, the value of ‘this‘ is determined mostly by the invocation context of the function and where it is called. (Read this reference)

  1. In order to resolve this problem, inject ‘this‘ as context by setting it up as the third parameter to _.each helper function
_.each(data, function(item : any) {
     item.name = this.formatName(item);
}, this);

2. There is one more solution too by saving the context in temporary variable before consuming ‘this’ in _.each

public testFunction() : void {
  var context = this;
  _.each(data, function(item : any) {
      item.name = context.formatName(item);
  });
}

 

Improve Performance of Web Page (Client Side) – Extended Version

Standard

Make fewer HTTP requests

Decreasing the number of components on a page reduces the number of HTTP requests required to render the page, resulting in faster page loads. Some ways to reduce the number of components include: combine files, combine multiple scripts into one script, combine multiple CSS files into one style sheet, and use CSS Sprites and image maps.

Use a Content Delivery Network (CDN)

User proximity to web servers impacts response times. Deploying content across multiple geographically dispersed servers(CDN) helps users perceive that pages are loading faster.

Avoid empty src or href

You may expect a browser to do nothing when it encounters an empty image src. However, it is not the case in most browsers. IE makes a request to the directory in which the page is located; Safari, Chrome, Firefox 3 and earlier make a request to the actual page itself. This behavior could possibly corrupt user data, waste server computing cycles generating a page that will never be viewed, and in the worst case, cripple your servers by sending a large amount of unexpected traffic.

Add Expires headers

Web pages are becoming increasingly complex with more scripts, style sheets, images, and Flash on them. A first-time visit to a page may require several HTTP requests to load all the components. By using Expires headers these components become cacheable, which avoids unnecessary HTTP requests on subsequent page views. Expires headers are most often associated with images, but they can and should be used on all page components including scripts, style sheets, and Flash.

Compress components with gzip

Compression reduces response times by reducing the size of the HTTP response. Gzip is the most popular and effective compression method currently available and generally reduces the response size by about 70%. Approximately 90% of today’s Internet traffic travels through browsers that claim to support gzip.

Put CSS at top

Moving style sheets to the document HEAD element helps pages appear to load quicker since this allows pages to render progressively.

Put JavaScript at bottom

JavaScript scripts block parallel downloads; that is, when a script is downloading, the browser will not start any other downloads. To help the page load faster, move scripts to the bottom of the page if they are deferrable.

Avoid CSS expressions

CSS expressions (supported in IE beginning with Version 5) are a powerful, and dangerous, way to dynamically set CSS properties. These expressions are evaluated frequently: when the page is rendered and resized, when the page is scrolled, and even when the user moves the mouse over the page. These frequent evaluations degrade the user experience.

Make JavaScript and CSS external

Using external JavaScript and CSS files generally produces faster pages because the files are cached by the browser. JavaScript and CSS that are inlined in HTML documents get downloaded each time the HTML document is requested. This reduces the number of HTTP requests but increases the HTML document size. On the other hand, if the JavaScript and CSS are in external files cached by the browser, the HTML document size is reduced without increasing the number of HTTP requests.

Reduce DNS lookups

The Domain Name System (DNS) maps hostnames to IP addresses, just like phonebooks map people’s names to their phone numbers. When you type URL http://www.yahoo.com into the browser, the browser contacts a DNS resolver that returns the server’s IP address. DNS has a cost; typically it takes 20 to 120 milliseconds for it to look up the IP address for a hostname. The browser cannot download anything from the host until the lookup completes.

Minify JavaScript and CSS

Minification removes unnecessary characters from a file to reduce its size, thereby improving load times. When a file is minified, comments and unneeded white space characters (space, newline, and tab) are removed. This improves response time since the size of the download files is reduced.

Avoid URL redirects

URL redirects are made using HTTP status codes 301 and 302. They tell the browser to go to another location. Inserting a redirect between the user and the final HTML document delays everything on the page since nothing on the page can be rendered and no components can be downloaded until the HTML document arrives.

Remove duplicate JavaScript and CSS

Duplicate JavaScript and CSS files hurt performance by creating unnecessary HTTP requests (IE only) and wasted JavaScript execution (IE and Firefox). In IE, if an external script is included twice and is not cacheable, it generates two HTTP requests during page loading. Even if the script is cacheable, extra HTTP requests occur when the user reloads the page. In both IE and Firefox, duplicate JavaScript scripts cause wasted time evaluating the same scripts more than once. This redundant script execution happens regardless of whether the script is cacheable.

Configure entity tags (ETags)

Entity tags (ETags) are a mechanism web servers and the browser use to determine whether a component in the browser’s cache matches one on the origin server. Since ETags are typically constructed using attributes that make them unique to a specific server hosting a site, the tags will not match when a browser gets the original component from one server and later tries to validate that component on a different server.

Make AJAX cacheable

One of AJAX’s benefits is it provides instantaneous feedback to the user because it requests information asynchronously from the backend web server. However, using AJAX does not guarantee the user will not wait for the asynchronous JavaScript and XML responses to return. Optimizing AJAX responses is important to improve performance, and making the responses cacheable is the best way to optimize them.

Use GET for AJAX requests

When using the XMLHttpRequest object, the browser implements POST in two steps: (1) send the headers, and (2) send the data. It is better to use GET instead of POST since GET sends the headers and the data together (unless there are many cookies). IE’s maximum URL length is 2 KB, so if you are sending more than this amount of data you may not be able to use GET.

Reduce the number of DOM elements

A complex page means more bytes to download, and it also means slower DOM access in JavaScript. Reduce the number of DOM elements on the page to improve performance.

Avoid HTTP 404 (Not Found) error

Making an HTTP request and receiving a 404 (Not Found) error is expensive and degrades the user experience. Some sites have helpful 404 messages (for example, “Did you mean …?”), which may assist the user, but server resources are still wasted.

Reduce cookie size

HTTP cookies are used for authentication, personalization, and other purposes. Cookie information is exchanged in the HTTP headers between web servers and the browser, so keeping the cookie size small minimizes the impact on response time.

Use cookie-free domains

When the browser requests a static image and sends cookies with the request, the server ignores the cookies. These cookies are unnecessary network traffic. To workaround this problem, make sure that static components are requested with cookie-free requests by creating a subdomain and hosting them there.

Do not scale images in HTML

Web page designers sometimes set image dimensions by using the width and height attributes of the HTML image element. Avoid doing this since it can result in images being larger than needed. For example, if your page requires image myimg.jpg which has dimensions 240×720 but displays it with dimensions 120×360 using the width and height attributes, then the browser will download an image that is larger than necessary.

Make favicon small and cacheable

A favicon is an icon associated with a web page; this icon resides in the favicon.ico file in the server’s root. Since the browser requests this file, it needs to be present; if it is missing, the browser returns a 404 error (see “Avoid HTTP 404 (Not Found) error” above). Since favicon.ico resides in the server’s root, each time the browser requests this file, the cookies for the server’s root are sent. Making the favicon small and reducing the cookie size for the server’s root cookies improves performance for retrieving the favicon. Making favicon.ico cacheable avoids frequent requests for it.

 

AngularJS: What and when to use controller, compile, pre-link and post-link?

Standard

Compile :

This is the phase where Angular actually compiles your directive. This compile function is called just once for each references to the given directive. For example, say you are using the ng-repeat directive. ng-repeat will have to look up the element it is attached to, extract the html fragment that it is attached to and create a template function.If you have used HandleBars, underscore templates or equivalent, its like compiling their templates to extract out a template function. To this template function you pass data and the return value of that function is the html with the data in the right places.The compilation phase is that step in Angular which returns the template function. This template function in angular is called the linking function.

Linking phase :

The linking phase is where you attach the data ( $scope ) to the linking function and it should return you the linked html. Since the directive also specifies where this html goes or what it changes, it is already good to go. This is the function where you want to make changes to the linked html, i.e the html that already has the data attached to it. In angular if you write code in the linking function its generally the post-link function (by default). It is kind of a callback that gets called after the linking function has linked the data with the template.

Controller :

The controller is a place where you put in some directive specific logic. This logic can go into the linking function as well, but then you would have to put that logic on the scope to make it “shareable”. The problem with that is that you would then be corrupting the scope with your directives stuff which is not really something that is expected. So what is the alternative if two Directives want to talk to each other / co-operate with each other? Ofcourse you could put all that logic into a service and then make both these directives depend on that service but that just brings in one more dependency. The alternative is to provide a Controller for this scope ( usually isolate scope ? ) and then this controller is injected into another directive when that directive “requires” the other one. See tabs and panes on the first page of angularjs.org for an example.

Controller function

Each directive’s controller function is called whenever a new related element is instantiated.

Officially, the controller function is where one:

  • Defines controller logic (methods) that may be shared between controllers.
  • Initiates scope variables.

Again, it is important to remember that if the directive involves an isolated scope, any properties within it that inherit from the parent scope are not yet available.

Do:
  • Define controller logic
  • Initiate scope variables
Do not:
  • Inspect child elements (they may not be rendered yet, bound to scope, etc.)

Compile function

Each directive’s compile function is only called once, when Angular bootstraps.

Officially, this is the place to perform (source) template manipulations that do not involve scope or data binding.

Primarily, this is done for optimisation purposes; consider the following markup:

<tr ng-repeat="raw in raws">
    <my-raw></my-raw>
</tr>

The <my-raw> directive will render a particular set of DOM markup. So we can either:

  • Allow ng-repeat to duplicate the source template (<my-raw>), and then modify the markup of each instance template (outside the compile function).
  • Modify the source template to involve the desired markup (in the compile function), and then allow ng-repeat to duplicate it.

If there are 1000 items in the raws collection, the latter option may be faster than the former one.

Do:
  • Manipulate markup so it serves as a template to instances (clones).
Do not
  • Attach event handlers.
  • Inspect child elements.
  • Set up observations on attributes.
  • Set up watches on the scope.

Pre-link function

Each directive’s pre-link function is called whenever a new related element is instantiated.

As seen previously in the compilation order section, pre-link functions are called parent-then-child, whereas post-link functions are called child-then-parent.

The pre-link function is rarely used, but can be useful in special scenarios; for example, when a child controller registers itself with the parent controller, but the registration has to be in a parent-then-child fashion (ngModelController does things this way).

Do not:
  • Inspect child elements (they may not be rendered yet, bound to scope, etc.).

Post-link function

When the post-link function is called, all previous steps have taken place – binding, transclusion, etc.

This is typically a place to further manipulate the rendered DOM.

Do:
  • Manipulate DOM (rendered, and thus instantiated) elements.
  • Attach event handlers.
  • Inspect child elements.
  • Set up observations on attributes.
  • Set up watches on the scope.

AngularJS: Textarea Auto Resize Directive

Standard

Custom directive that resize text area as per user key input or through paste/cut

Over the years I have seen many solutions for this problem, so I have written angualr directive to resolve this issue. I have prefer vertical resize because horizontal resize strikes me as being a mess, due to word-wrap, long lines, and so on, but vertical resize seems to be pretty safe and nice. Please note instead of clientHeight attribute use scrollHeight

Features

  • On key input.
  • With pasted text (right click & ctrl+v).
  • With cut text (right click & ctrl+x).
  • With pre-loaded text.
  • With all textarea’s (multiline textbox’s) site wide.
  • Is w3c validated.

Github Link

Angular Code:

(function () {
  'use strict';

  angular
      .module('sampleApp' , [])
      .directive('autoResize', autoResize);

      autoResize.$inject = ['$timeout'];

      function autoResize($timeout) {

          var directive = {
              restrict: 'A',
              link: function autoResizeLink(scope, element, attributes, controller) {

                  element.css({ 'height': 'auto', 'overflow-y': 'hidden' });
                  $timeout(function () {
                      element.css('height', element[0].scrollHeight + 'px');
                  }, 100);

                  element.on('input', function () {
                      element.css({ 'height': 'auto', 'overflow-y': 'hidden' });
                      element.css('height', element[0].scrollHeight + 'px');

                  });
              }
          };

          return directive;
      };
})();

Angular HTML Code:

<textarea auto-resize style="resize: none;"></textarea>

Initial State:

capture png

After user input through keystrokes:

capture

After user input through paste:

capturez png

AngularJS: Dynamic Validation Directive

Standard

Custom directive that allows text only, number only, special character only or allow everything as per user choice.

Github Link

Angular Code:

(function () {
    'use strict';

    angular
        .module('sampleApp')
        .directive('validate', validate);

    function validate() {
        var directive = {
            restrict: 'EA',
            scope: {
                regex: '=criteria'
            },
            require: 'ngModel',
            controller: validateController,
            link: validateLink
        };

        return directive;
    }

    validateController.$inject = ['$scope'];

    function validateController($scope) {
    }

    function validateLink(scope, element, attrs, ngModelCtrl) {

        element.on('focus', function (e) {
            ngModelCtrl.$parsers.push(validateInput);
        });

        function validateInput(input) {
            if (input) {
                var regex = new RegExp(scope.regex);
                var newValue = input.replace(regex, '');
                if (newValue !== input) {
                    ngModelCtrl.$setViewValue(newValue);
                    ngModelCtrl.$render();
                }
                return newValue;
            }
            return undefined;
        }
    }

})();

Output:

2016-07-01 14_07_02-mozilla firefox

AngularJS : Tree Component

Standard

Tree Control is an AngularJS component that cad add siblings, child and remove them. It doesn’t depend on jQuery.

I have tried number of tree control but none is available out in open source community which can assist you to add siblings too. Since I want to control number of childs that can be added to single node. So I came up with my own tree control implementation.

Features

  • Data binding for the tree model
  • Data binding for the selected node in the tree
  • Adding siblings
  • Customize number of childs to be added on a single node(Default: 6)
  • Remove node
  • Recusive controller and Html code
  • Can be customized with CSS

Github Link

Initial State:

2016-07-06 14_28_36-index html

After adding multiple siblings and children:

2016-07-06 14_34_26-index html

Alert if you remove parent with children:

2016-07-06 14_34_43-index html

Alert if number of childs exceeds:

2016-07-06 14_38_26-index html

 

Angular Code:

(function () {
    'use strict';
    
    var app = angular
        .module('sampleApp', []);
    
    app.controller('HomeController', homeController);
 
    homeController.$inject = [];
 
    function homeController() {
        var vm = this;
 
        init();
 
        function init() {
            vm.detailList = [];
            vm.ID = 0;
            vm.parentRecord = {};
            addRootNode();
            vm.AddSibling = AddSibling;
            vm.AddChild = AddChild;
            vm.Delete = Delete;
        }
 
        ////////////////////////////Implementation//////////////////////////////////////
 
        function AddSibling(item) {
            if (item.parentId == 0) {
                addRootNode();
            }
            else {
                findParentRecord(vm.detailList, item.parentId);
                if (vm.parentRecord) {
                    AddChild(vm.parentRecord);
                }
            }
        }
 
        function AddChild(item) {
            var depth = findNodeLevel(vm.detailList, item.ID);
            if (depth < 7) {
                vm.ID = vm.ID + 1;
                item.nodes.push({
                    nodes: [],
                    parentId: item.ID,
                    ID: vm.ID
                });
            }
            else
                alert('maximum level has been reached');
        }
 
        function Delete(item) {
            if (item.nodes.length > 0)
                alert('delete children first');
            else {
                DeleteChild(vm.detailList, item.parentId, item);
            }
        }
 
        ////////////////////////////Helping Function//////////////////////////////////////
 
        function addRootNode() {
            vm.ID = vm.ID + 1;
            vm.detailList.push({
                nodes: [],
                parentId: 0,
                ID: vm.ID
            });
        }
 
        function findParentRecord(arr, parentId) {
            for (var i in arr) {
                if (typeof (arr[i]) == "object") {
                    if (arr[i].ID == parentId) {
                        vm.parentRecord = arr[i];
                        break;
                    }
                    else
                        findParentRecord(arr[i], parentId);
                }
            }
        }
 
        function DeleteChild(arr, parentId, item) {
            for (var i in arr) {
                if (typeof (arr[i]) == "object") {
                    if (arr[i].ID == parentId) {
                        var childrenList = arr[i].nodes;
                        var index = findIndex(childrenList, item.ID);
                        if (index > -1)
                            childrenList.splice(index, 1);
                        break;
                    }
                    else
                        DeleteChild(arr[i], parentId, item);
                }
            }
        }
 
        function findIndex(arr, selectedItemID) {
            for (var i in arr) {
                if (arr[i].ID == selectedItemID)
                    return i;
            }
            return -1;
        }
 
        function findNodeLevel(arr, id) {
            var level = 1;
            findParentRecord(arr, id)
            while (vm.parentRecord.parentId > 0) {
                level = level + 1;
                findParentRecord(arr, vm.parentRecord.parentId);
            }
            return level;
        }
    };
})();

 

Angular HTML Code:

<html>
    <body ng-app="sampleApp" class="ng-cloak">
        
                             
                                                                                                                                               
                            
  •                     
                
            </script>             
                
                
                    
                            
  •                     
                
            </div>             

AngularJS: Prevent changes in parent scope until Save operation is performed in modal

Standard

It happens usually when ever you are using ng-repeat in parent page and pass that row data to Modal for editing purpose, any changes made in modal is reflected directly in parent page grid without saving the modal updated data.

2016-02-18 09_01_34-HomePage

As you can see I am changing Course name and it is reflected directly in grid at main page.

Solution:

What you would need is to clone your model, prior to showing your edit modal, and when a user clicks on closeModal() you would reassign your model to the cloned value.

function DialogController($mdDialog, courseData) {
 
            var vmPop = this;
            initPopUp();
 
            function initPopUp() {
                vmPop.course = [];
                if (courseData)
                    vmPop.course = angular.copy(courseData);
            }
  }

As you can see I am passing courseData to dialog modal controller, before assigning it to modal scope variable (vmPop.course), I am creating a copy of source, which is an object and then assigning it to vmPop.course variable.

Angular Docs for angular.copy