Why and how to abort an ongoing angular $http request

Long time ago I wrote a blog about aborting ongoing ajax request in jQuery here Why and how to abort an ajax call in jQuery.

In this post we will do the same using angularjs. Before going into how we do it lets discuss few things about why we need it.

Lets take a simple example, we need a search functionality. For this we take an input field and attach a keyup event on which we will make a $http request to server with typed text and get the result.

<input type=”text” ng-model=”search” ng-keyup=”search()”>

Create a service function for http request and call the service function in controller like

service.js

service.search = function(searchString){
    $http.post(url,{search:searchString}).then(
        function(response){
            //success callback
        }, function(response){
            //error callback
        }
    );
};

 

controller.js

$scope.search = '';

$scope.search = function(){
    searchService.search($scope.search);
};

 

These code will be well enough to implement simple search functionality.

But there is a problem, if you want to search something like ‘angular’ then there will be 7 http requests in place because search function called on keyup event only. So one call for ‘a’ then another for ‘an’ then another for ‘ang’ and so on.

Now these  are asynchronous calls and very much unpredictable. You can’t predict in which sequence request will be completed, its never guranted that the sequence you made the request, result/response will come in same sequence. It may happen that ajax request with ‘angular’  gets finished before the request for ‘angula’ gets over. Though the request for ‘angula’ finished last so user will see the result for ‘angula’ even if search keyword is ‘angular’ which is very bad user experience.

To overcome this, we need to abort/cancel the previous request is in process before we make a new request. To achieve this we will take help of angular $q service, $q is a service that helps you run functions asynchronously, and use their return values (or exceptions) when they are done processing.

We will create a defer object using $q and will take a variable to have the status of ongoing ajax request. By default we will take that value as false and will set to true when an ajax started and will set it back to false when ajax completes. So anytime if that variable returns true  then we will understand there is some ongoing ajax call which we need to cancel.

$http request’s config parameter has a timeout option through which we can timeout an ajax request.

timeout – {number|Promise} – timeout in milliseconds, or promise that should abort the request when resolved.

So each and every request we will create a promise and before initiating another call we will check if any ongoing request, if so then we will resolve the promise of that request which will automatically abort or timeout that request.

So the new service function will be like

var cancelSearch = $q.defer(); //defer object
var searchResolve = false; //status of a request

service.search = function(searchString){
    //checking for any other ongoing call
    if(searchResolve){
       //resolving previous request's defer which will abort that ajax call
       cancelSearch.resolve('search aborted');
    }

    cancelSearch = $q.defer(); //create new defer for new request
    searchResolve = true; //set the request status to true/ongoing

    $http.post(url,{search:searchString},{timeout:cancelSearch.promise})
    .then(
        function(response){
            //success callback
            searchResolve = false; //set the request status to completed
        }, function(response){
            //error callback
        }
    );
};

 

NOTE: Remember to inject $q service to your controller/service /directive

 

 

ES6: Template Literals

Template literals is the new feature introduce in ES6. Previously string manipulation was very restricted. Was not able to parse variables in sting, had to concatenate. Same for multi line string.

In ES6 template string introduce by using back-ticks(` `) instead of single or double quotes for strings. A template string could  be written as :

Synatax

`Hello World!!`
var msg = `Hello Word!!`

 

Multiline String

For multiline string we need to use ‘\n’ for line break but in template literals string in next line will automatically treated as new line.

Syntax for multiline string

console.log("Hi Jon Doe.\n"+
"How are you?");
//"Hi Jon Doe.
//How are you?"

 

Syntax for same multiline string using template literals

console.log(`Hi Jon Doe.
How are you?`);
//"Hi Jon Doe.
//How are you?"

 

String Substitution

One of the best feature of templating, allows any valid javascript expression in template.

Syntax we use

var person = {name:'Jon Doe', age:42, sex:'Male'};
console.log(person.name +' is a '+person.age+' years old '+person.sex);
"Jon Doe is a 42 years old Male"

Syntax use string substitution

var person = {name:'Jon Doe', age:42, sex:'Male'};
console.log(`${person.name } is a ${person.age} years old ${person.sex}`);
"Jon Doe is a 42 years old Male"

Few more examples

var a = 10;
var b = 10;

console.log(`${a} + ${b} = ${a + b}`); // 10 + 10 = 20
console.log(`${a} * ${b} = ${a * b}`); // 10 * 10 = 100
console.log(`${a} ^ ${b} = ${Math.pow(a , b)}`); // 10 ^ 10 = 10000000000

 

var person = {name:'Jon Doe', age:42, sex:'Male'};

function salutation(sex){
  return (sex == 'Male') ? 'Mr.' : 'Miss.';
}

console.log(`Hello ${salutation(person.sex)} ${person.name}`);
//Hello Mr. Jon Doe

console.log(`Hello ${salutation(person.sex)} ${person.name.toUpperCase()}`);
//Hello Mr. JON DOE

 

Tagged template literals

Tagged template literals helps us to modify the output of a template literals using a function. The first argument contains an array of string literals . The second, and each argument after the first one, are the values of the processed substitution expressions . In the end,  function returns processed string.

How we write it

getUrl([ "http://example.com/product?category=", "&id="],category, id);

How it be

getUrl`http://example.com/product?category=${category}&id=${id}`;

 

Lets see it in details

var category = 'demo', id = 201;
function getUrl(strings, val1, val2){
    return strings[0]+val1+strings[1]+val2;
}
getUrl([ "http://example.com/product?category=", "&id="],category, id);
"http://example.com/product?category=demo&id=201"

ES6 approach

var category = 'demo', id = 201;
function getUrl(strings, ...values){
    return strings[0]+values[0]+strings[1]+values[1];
}
getUrl`http://example.com/product?category=${category}&id=${id}`;
"http://example.com/product?category=demo&id=201"

ES6: Constant and block scoped variables

Constant

In javascript we can’t declare a variable as constant. But we can achieve it by using Object.defineProperty()

This method accepts three arguments: the object on which the property should be added or modified, the name of the property, and a descriptor object. The properties on the descriptor object match the attribute names: configurable, enumerable, writable, and value.

[[Configurable]] — Indicates if the property may be redefined by removing the property via delete, changing the property’s attributes, or changing the property into an accessor property.

[[Enumerable]] — true if and only if this property shows up during enumeration of the properties on the corresponding object.

[[Writable]] — Indicates if the property’s value can be changed. By default, this is true for all properties defined directly on an object.

[[Value]] — Contains the actual data value for the property. This is the location from which the property’s value is read and the location to which new values are saved. The default value for this attribute is undefined.

So to create a constant,  declare a global variable which will be part of global or window object  which value can’t be changed or alter or deleted.

Object.defineProperty(typeof global === "object" ? global : window, "PI", {
    value: 3.141593,
    enumerable: true,
    writable: false,
    configurable: false
});
PI => 3.141593

 

ES6 introduce const to declare constant which can’t be altered, deleted or re-declared.

const PI = 3.141593

PI => 3.141593

 

const VERSION = 2.0;

// this will throw an error
VERSION = 2.3;

// will print 2.0
console.log(VERSION);

// trying to redeclare a constant throws an error
const VERSION = 2.7;

// the name VERSION is reserved for constant above, so this will also fail
var VERSION = 3.0;

 

Block scoped variable

ES6 introduce a new keyword let to declare block scoped variable.  Let’s see the difference between var and let

function varTest() {
    var x = 1;
    if (true) {
        var x = 2;  // same variable!
        console.log(x);  // 2
    }
    console.log(x);  // 2
}

 

function letTest() {
    let x = 1;
    if (true) {
        let x = 2;  // different variable
        console.log(x);  // 2
    }
    console.log(x);  // 1
}

 

More Examples

var callbacks = [];
for (var i = 0; i <= 2; i++) {
    callbacks[i] = function() { return i * 2; };
}

callbacks[0]() => 6
callbacks[1]() => 6
callbacks[2]() => 6

 

This one is the classic example of closures. When all functions get called that time i reached to maximum value 3. To avoid this we use anonymous function.

var callbacks = [];
for (var i = 0; i <= 2; i++) {
    (function (i) {
        callbacks[i] = function() { return i * 2; };
    })(i);
}

callbacks[0]() => 0
callbacks[1]() => 2
callbacks[2]() => 4

 

In above example we handle closure and passed i as a parameter to the anonymous function and i became local inside that function.

In ES6 we can do it without handling closure by declaring in blocked scope

var callbacks = [];
for (let i = 0; i <= 2; i++) {
    callbacks[i] = function() { return i * 2; };
}

callbacks[0]() => 0
callbacks[1]() => 2
callbacks[2]() => 4

 

ES6: Parameter Handling

Parameter handling in ES6 gets improved a lot and makes developers life easy. We will see how it got better against ES5

Default parameter values

In ES5 it was quite complicated to set a default value to a function parameter if no value passed for that. Normally we checked that parameter defined or not and if undefined then we set it to default value like

function myFunc(name, age, sex){
    if(name === undefined)
        name = 'Jon Doe';
    if(age === undefined)
        age = 18;
    if(sex === undefined)
        sex = 'Male';
   return name+' is a '+age+' years old '+sex;
}

myFunc() => "Jon Doe is a 18 years old Male"
myFunc('Junior Doe', 5) => "Junior Doe is a 5 years old Male"
myFunc('Jane Doe', 49, 'Female') => "Jane Doe is a 49 years old Female"

Or like

function myFunc(name, age, sex){
    var name = name || 'Jon Doe';
    var age = age || 18;
    var sex = sex || 'Male';
   return name+' is a '+age+' years old '+sex;
}

myFunc() => "Jon Doe is a 18 years old Male"
myFunc('Junior Doe', 5) => "Junior Doe is a 5 years old Male"
myFunc('Jane Doe', 49, 'Female') => "Jane Doe is a 49 years old Female"

In ES6 we don’t need to check the parameter and then set it default value. We can do it directly in function definition like

function myFunc(name = 'Jon Doe', age = '18', sex = 'Male'){
   return name+' is a '+age+' years old '+sex;
}

myFunc() => "Jon Doe is a 18 years old Male"
myFunc('Junior Doe', 5) => "Junior Doe is a 5 years old Male"
myFunc('Jane Doe', 49, 'Female') => "Jane Doe is a 49 years old Female"

 

Passing undefined

In function if all parameters values are set to default but if we want to use few arguments default value.

Like

function myFunc(name = 'Jon Doe', age = '18', sex = 'Male')

 

We want to call this function with name and sex and want age to be default value then we need to pass undefined (not null). undefined  always replace with default value if any.

 

myFunc('Jane Doe', undefined, 'Female') => "Jane Doe is a 18 years old Female"

 

Call time evaluation

All default arguments get evaluated while function called and new object gets created for each call like.

function fruits(name, all = []){
    all.push(name);
    return all;
}

fruits('apple') => ['apple']
fruits('mango') => ['mango'] not ['apple', 'mango']

 

Defaults are available to next defaults

Parameters already fetched are available to next default parameters

function fruits(fruits, fewFruits = 'Few '+fruits, manyFruits = 'Many '+fruits){
    return [fruits, fewFruits, manyFruits];
}

fruits('Mangoes') => ['Mangoes', 'Few Mangoes', 'Many Mangoes']

 

Rest Parameters

Each function has its own arguments array. arguments array created automatically inside each function and contains all parameters passed to function.

function myFunc(name, age)
myFunc('Jon Doe', 24)

Here myFunc arguments will contain name and age both. We can loop through arguments and get all values.

function myFunc(name, age)
myFunc('Jon Doe', 24, 'Female', 'Hispanic', 'French')

In above call we passed  3 extra parameter for sex, ethnicity and language. Though myFunc function doesn’t has any named parameter for those extra parameters, we can’t access those values directly. We can get those from arguments.

Here arguments  contains all named as well as unnamed parameters. If we want to retrieve all unnamed parameters then there are no direct way to get in ES5. Only way to get it by slicing arguments

function myFunc(name, age){
   var extras = Array.prototype.slice.call(arguments, myFunc.length);
   //or
   // var extras = Array.prototype.slice.call(arguments, 2);
   return extras;
}
myFunc('Jon Doe', 24, 'Female', 'Hispanic', 'French') => ['Female', 'Hispanic', 'French']

NOTE: functionName.length returns the number of parameters that function expects.

In ES6 a new property introduced called rest parameters which holds all unnamed parameters only like

function myFunc(name, age, ...extras){
   return extras;
}
myFunc('Jon Doe', 24, 'Female', 'Hispanic', 'French') => ['Female', 'Hispanic', 'French']

 

Example

Here we are taking an example, calculation power of numbers where first parameter is the power and second the rest parameter which contains an array of elements.

function power(power, ...theArgs) {
   return theArgs.map(function (element) {
      return Math.pow(element, power);
   });
}
power(2,1,2,3,4,5) => [1,4,9,16,25]
power(3,1,2,3,4,5) => [1,8,27,64,125]

 

Better Examples

If a functions expects few parameters then while we call that function, we can’t pass all parameters in an array, need to pass individually like

function myFunc(name, age, sex)
var args = ['Jon Doe', 24, 'Male'];
myFunc(args) //doesn't work
function myFunc(name, age, sex)
var args = ['Jon Doe', 24, 'Male'];
myFunc(args[0], args[1], args[2]) // works
myFunc.apply(null,args) // works

In ES6 it’s like

function myFunc(name, age, sex)
var args = ['Jon Doe', 24, 'Male'];
myFunc(...args) //works

 

function myFunc(name, age, sex, ethnicity, language)
var args = [ 24, 'Male', 'Hispanic'];
myFunc('Jon Doe', ...args, 'French') //works

Call ajax in parallel instead of in a chain

We know ajax is an asynchronous call and doesn’t halts other ajax calls if calls are made same time.

Suppose I have a button and clicking on that button fires two ajax calls.

So when i click the button then both ajax get called same time and these calls don’t have any dependency to each other.

But there are situation where we need to do something else when both ajax call get completed like refreshing a section or showing success message.
For doing this we need know on which state all my ajax are completed. And its not necessary that ajax will be get completed in the same sequence I called.

$.post('page1.php',function(data1){});
$.post('page2.php',function(data2){});
$.post('page3.php',function(data3){});

Suppose i have these 3 ajax calls. Now i need to show an success message to user when all these are completed.
There are no way to do it if we make ajax calls in parallel.

So to make it simplified we made ajax call in chain means we call an ajax first and when that ajax completes then we call the 2nd ajax and so on.
When my last ajax call gets completed then we show the required message to the user because we are very sure that my ajax call gets fired because only when all my previous ajax are completed successfully.

Like

$.post('page1.php',function(data1){
    $.post('page2.php',function(data2){
        $.post('page3.php',function(data3){
            //Here we make sure all ajax call completed
        });
    });
});

Above code doesn’t has any problem at all, that code structure is very well trusted and never fails.

But don’t you think you are just wasting time because ajax will be call one by one and next subsequent call will fired only when previous one completed successfully.
Also ajax are ment to call asynchronously so you will able to call all 3 ajax parallel.

Now if you are able to detect the complete point of all 3 ajax calls then it will be big performace boosting.

We can do this by using jQuery deferred object.

We will use $.when() function, inside this function we will pass all ajax call and we will catch all ajax state using $.done() or $.then().

$.when(
    $.post('page1.php'),
    $.post('page2.php'),
    $.post('page3.php')
).done(function(data1, data2, data3){
    //here you will all 3 ajax calls response available when all
ajax call get completed.
});
$.when(   
    $.post('page1.php'),
    $.post('page2.php'),
    $.post('page3.php')
).then(function(data1, data2, data3){
    //here you will all 3 ajax calls response available when all
ajax call get completed.
});

If you want to call a specific success function if all gets completed successfully or call a failure function if one of the call failed then do it like.

$.when(
    $.post('page1.php'),
    $.post('page2.php'),
    $.post('page3.php')
).then(successCallBack, failureCallBack);

Why and how to abort an ajax call in jQuery.

Lets think about you have an input field and you attached an autocomplete function to that input field.

For an autocomplete functionality what we need to do is attaching a keyup event handler to that input field and every keyup call an ajax to get the desire results.

Lets think below is the input field
<input id=”search” name=”search” type=”text” >

And a div where we show the autocomplete list
<div id=”result”></div>

And the code for an autocomplete function is like

$(function(){
    $('#search').keyup(function() {
        var q = $(this).val();
        $.ajax({
            type: 'POST',
            data: 'q=' + q,
            url: 'AJAX_URL',
            success: function(response) {
                $('#result').html(response).show();
            }
        });
    });
});

Above code works great and you will have a nice autocomplete feature in place.

But did you think when you search by more than one character then what happen.

A new ajax request will be made for each and every character you entered. Lets take an example, you want to see an autocomplete list for “John”.

When you entered “J”, an ajax call will be made for “J”, then when you entered “o”, another call will be made for “Jo” and so on.

So to search “John”, you have 4 ajax calls for “J”, “Jo”, “Joh” and “John” and all 3 ajax response are useless to you except “John” one.

But you are thinking at the end of all ajax call user will get response of “John” and will see the correct response. And here you made the mistake. Remember ajax are asynchronous so it never happen sequentially.  You may call all ajax in a sequence but there are no guarantee that you will get the response in same sequential order.

Lets take the above example. You have 4 ajax calls in place. Though these are asynchronous calls, it may happen that you get response of ajax 4 before ajax 3 completes. So you were expecting results for “John” but you end up getting result of “Joh” which is weird to user.

Take another real life example. Suppose we are working on an e-commerce website where we list lots of product with different filter option.

Lets say we have selected t-shirts and in this page we have filter options for brands and all brands are associated with a checkbox to filter the list.

Here we made an ajax request when we click on a checkbox and filter the list.

Lets think i checked ‘Adidas’, ‘Nike’, ‘Reebok’ and ‘Puma’ and i will have 4 ajax call in place like

ajax 1: ‘Adidas’
ajax 2: ‘Adidas, Nike’
ajax 3: ‘Adidas, Nike, Reebok’
ajax 4: ‘Adidas, Nike, Reebok, Puma’

Though these are asynchronous call it may be possible you get ajax 1 response at the end. So what user will see? He will be seeing his all 4 filter options are checked but he is just seeing filter list by ‘Adidas’. Don’t you think, this is a very bad user experience?

So how we can solve this.

We will do one thing, before calling any ajax, we will check if there any pending ajax request for same ajax function. If there are any pending ajax call then we will cancel those and make a fresh/new ajax call.

jQuery provides a great function to cancel any ajax call any time called abort(). We will use this abort() function to cancel any pending ajax before calling the same.

We will take an variable which will store the status of any pending ajax call and default value will be set to null means no ajax call in place like

var progress = null;

This variable value will be updated when a ajax call is made like

progress = $.ajax();

We will set this variable value to null again when this ajax call completes like

complete: function(data) {
     progress = null;
 }

So progress has the latest ajax status. Before making any new ajax call we will check progress’s status and will see progress is null or not.

If progress isn’t null then we will abort the previous call then we will made the new call like.

beforeSend : function()    {
     if(progress != null) {
         progress.abort();
     }
 }

And the complete function will be like

$(function(){
    var progress = null;
    $('#search').keyup(function() {
        var q = $(this).val();
        progress = $.ajax({
            type: 'POST',
            data: 'q=' + q,
            url: 'AJAX_URL',
            beforeSend : function() {
                //checking progress status and aborting pending request if any
                if(progress != null) {
                    progress.abort();
                }
            },
            success: function(response) {
                $('#result').html(response).show();
            },
            complete: function(){
                // after ajax xomplets progress set to null
                progress = null;
            }
        });
    });
});

How to toggle an attribute in jQuery

In jQuery 1.9 version toggle() function deprecated. New toggle() helps you to hide and show elements with animation and easing effects.

Now if you need a function for toggling an attribute value on click event, how you will do it because jQuery doesn’t provides any function for this. For doing this you can write your own function and can use it in same way you use any other jQuery function.

$.fn.toggleAttr = function(attrName, attrVal1, attrVal2) {
return this.each(function() {
var self = $(this);
if (self.attr(attrName) == attrVal1)
self.attr(attrName, attrVal2);
else
self.attr(attrName, attrVal1);
});
};

Now this function will helps you toggle any attribute.

Lets see an example

Suppose i am having an image in page

<img src=”myUrl/test1.jpg” alt=”img1″ title=”img1″ id=”img”>

Now suppose i need to change image to test2.jpg when some click on test1.jpg and the reverse one. So we can do it using above function like

$(function() {
$(‘#img’).click(function(){
$(‘#img’).toggleAttr(‘src’, ‘myUrl/test1.jpg’, ‘myUrl/test2.jpg’);
$(‘#img’).toggleAttr(‘alt’, ‘img1’, ‘img2’);
$(‘#img’).toggleAttr(‘title’, ‘img1’, ‘img2’);
});
});

How to use HTML for jQuery dialog title

Latest version of jQuery UI doesn’t allow HTML as dialog title to avoid vulnerabilities. It only allows text. So if you want to show some icon or custom design for the title then you don’t have a way to do it from title property.

But we can do it by extending the dialog widget.

1st we will add an extra option to dialog property called titleIsHtml. We will set it as true if we want to use HTML for dialog title or false for text or even we can leave it so by default it will be text.

$(“#myDialog”).dialog({
        modal: true,
        title: “<div class=’widget-header widget-header-small’><h4 class=’smaller’><i class=’ic-file ‘></i> My Dialog</h4></div>”,
        titleIsHtml: true,
        autoOpen: false,
        width:800,
        height:’auto’
});

Now we are extending the dialog property like

$.widget(“ui.dialog”, $.extend({}, $.ui.dialog.prototype, {
        _title: function(title) {
            var $title = this.options.title || ‘&nbsp;’
            if( (“titleIsHtml” in this.options) && this.options.titleIsHtml == true )
                title.html($title);
            else title.text($title);
        }
}));

Here we are checking the titleIsHtml property of dialog, if it is set and true then we are setting dialog title using jQuery’s html() function which will allow to set HTML in dialog.

If titleIsHtml isn’t set or false then we are using jQuery’s text() function to set the title which will just put raw text as dialog title