AngularJS: Sometime OrderBy does not work in ng-repeat

You must noticed that sometime OrderBy does not works, sometime works very nicely.

For example: if you have the data with following structure:
JavaScript

$scope.friends = [
      { name: 'John', phone: '555-1212', age: 10 },
      { name: 'Mary', phone: '555-9876', age: 19 },
      { name: 'Mike', phone: '555-4321', age: 21 },
      { name: 'Adam', phone: '555-5678', age: 35 },
      { name: 'Julie', phone: '555-8765', age: 29 }
];

Then it works if you code use the following code:
HTML

<tr ng-repeat="friend in friends | orderBy:'-age'">
      <td>{{friend.name}}</td>
      <td>{{friend.phone}}</td>
      <td>{{friend.age}}</td>
    </tr>

But if your data structures changes a bit as follows:
JavaScript

$scope.peoples = [{
      'friend':{ name: 'John', phone: '555-1212', age: 10 },
      'relative':{ name: 'Mary', phone: '555-9876', age: 19 },
      'cousin':{ name: 'Mike', phone: '555-4321', age: 21 },
      'uncle':{ name: 'Adam', phone: '555-5678', age: 35 },
      'aunt':{ name: 'Julie', phone: '555-8765', age: 29 }
}];

HTML

<tr ng-repeat="people in peoples | orderBy:'-age'">
      <td>{{people.name}}</td>
      <td>{{people.phone}}</td>
      <td>{{people.age}}</td>
</tr>

Now, order by will not. This is because, previous data structure was an array and order by works fine on array. Now it is an Object. Order by does not works on Objects. So, first you have to make this objects to an array and then it will fine.

To make this object to an array we will use an filter. Following code will create an filter for throughout the module:
JavaScript

 ng.module('yourmodule').filter('toArray', function() {
  return function(obj, addKey) {
    if (!(obj instanceof Object)) {
      return obj;
    }

    if (addKey === false) {
      return Object.values(obj);
    } else {
      return Object.keys(obj).map(function(key) {
        return Object.defineProperty(obj[key], '$key', {enumerable: false, value: key});
      });
    }
  };
});

Now you just add this filter to html code:
HTML

    <tr ng-repeat="people in peoples | toArray | orderBy:'-age'">
      <td>{{people.name}}</td>
      <td>{{people.phone}}</td>
      <td>{{people.age}}</td>
    </tr>

😉 Order by will work like magic. Cheers!

View complete code in Plnkr.co

Advertisements

AngularJS: Add enter key to check/uncheck the check box

Sometimes clients want something different. We all know that if we check/uncheck the check box through keyboard then we have do it by space bar. But sometimes clients wants this through enter key in addition to the space bar specially for keyboard only user. So, this code can reduce your effort to write your own.

For AngularJS:

// Assume that your main module name is app, it can be anything you like.
var App = angular.module('app', []);

// Adding as directive.
App.directive('input', ['$interval', function($interval) {
    return {
      restrict: 'E', // It restricts that the directive will only be a HTML element (tag name), not an attribute.
      link: function(scope, elm, attr) {
        if (attr.type === 'checkbox') {
          elm.on('keypress', function(event) {
            var keyCode = (event.keyCode ? event.keyCode : event.which);
            if (keyCode === 13) {
              event.preventDefault(); // only when enter key is pressed.
              elm.trigger('click');
              scope.$apply();
            }
          });
        }
      }
    };
  }
]);

Same thing on jQuery is pretty easy:

jQuery(document).ready(function() {
  jQuery('input:checkbox').keypress(function(event) {
    var keyCode = (event.keyCode ? event.keyCode : event.which);
    if (keyCode === 13) {
      event.stopPropagation(); // only when enter key is pressed.
      this.trigger('click');
    }
  });
});

Very Basics of Angular JS

Recent years was a bright year for JavaScript developers, many JavaScript frameworks were born. With the advent of these frameworks, it can be quite a pain for developers to choose one suitable framework. Today we will talk with another JavaScript framework, which is Angular JS. This is very basic level discussion to kick start the Angular JS SPA (Single Page Application) Development.

Angular JS claims itself as super heroic JavaScript framework. Angular enhances HTML for web apps. It has functionalities to ease the process of developing web apps. HTML was first intended to build dynamic web apps that are Angular. Angular is what HTML would have been if it were designed to build web apps.

Before dig deeper to Angular features, we want to let you know that Angular is brought to you by Google. At least this fact can give you assurance Angular comes from the right people you can trust.

A strong understanding of basic JavaScript will be required to use Angular. If you feel that you’re beginner, keep going, Angular is not necessarily for advanced developers, but you will be dealing with a lot of objects so you have to be familiar with object oriented paradigm in JavaScript.

Digging into Angular JS:

– Angular JS is such a powerful SPA framework which allows writing client side application without JS coding or JS knowledge.

  • Here is an example how a simple app can be built without having any JS code.

– Angular JS is a full featured SPA Framework. It has all that needs for a good SPA[Single Page Application].

– So, the Big Picture of the Angular JS is like follows:

– Now, digging more deeper-

  • Directives and Data Binding: Directives refers to a feature to extends the vocabulary of HTML, it also can be seen as a way to teach your browser new tricks . With directive feature, we can create new HTML vocabulary that the browser will understand what it means and what it should do. You will find here all directives: http://docs.angularjs.org/api/ng#directive

  • View & Controller: between view controller there is a term $scope. Scope is a glue between view and controller. We also can call it Dependency Injector.

– Controller doesn’t know about the view. So, when a view calls a controller, it injects the scope automatically.

– View can be a full body DOM or a particular div. Different div can be used as different view in same html. Here the scope is the div in which the controller has declared.

  • Module:

– In Big Picture of Angular JS we saw Module is the root of everything. For a single page only one module can be added, but module can add many other module inside it by mentioning the dependencies or other module.

– Here is how module is defined with and without dependency- [We call it Dependency Injection]

  • Routers: In a configuration we can define the router. Router takes the URL after a “#” and loads related views. View can be defined in different html file.

  • Factories: factories are similar to Data-Model. There are four things in Angular JS for manage data. These are Factory, Service, Provider, Value.

registerForRemoteNotificationTypes: is not supported in iOS 8.0 and later, so?

Some body must have faced the problem like me that the registerForRemoteNotificationTypes: doesn’t works on iOS 8 or later device. I found the solution and I think this is the better way to keep backwards compatibility and make workable the remote notification for iOS 8.0 and later versions if we go with this approach, it is working for my case and will hope work for you. Also pretty easy to understand.

So to register write this code in AppDelegate’s - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { method:


    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
    {
        [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    }
    else
    {
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:
             (UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)];
    }

Now you will get a confirmation dialog at the starting time. if you all this app for push notifications, then you will get the device token for notification service from following delegate:(if supports all the versions we have)

#pragma mark - Notification delegates
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSLog(@"content---%@", token);
    
}

If it fails for any reason like certification error or any other reason, following delegate will be called.

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
    
    NSLog(@"Error %@", err);
    
}

So, now you have device token and you can do anything you like..

Tracking source URL with Google Analytic when redirecting by .htaccess

I got a situation like client have some URLs but the content or path doesn’t exists. So, clients need to redirect these URLs to other page. In addition he wanted to know, does the user came directly to that page or came through redirecting from those sources. So, I found a solution that worked for me and I liked to share it with you guys so that it solves your needs if your in the same situation. As the destination page already had the GA codes, I went through .htaccess solution. I just added two line codes in the .htaccess file as below: Consider http://yourdomain.com/abc.php is the source and http://yourdomain.com/xyz.php is the destination.

 
RewriteCond %{REQUEST_URI} ^/abc.php   
RewriteRule ^abc.php(.*)$ http://yourdomain.com/xyz.php?utm_source=redirects&amp;utm_medium=abc.php&amp;utm_campaign=301_Redirects [L,R=301]
 

So three things you need to add:

  1. utm_source=redirects
  2. utm_medium=abc.php (which is the source url)
  3. utm_campaign=301_Redirects

Now browse the source URL and you will be redirected to destination page. And then go to your GA account and see in real time view, you will found this URL is listed as redirect source.

I am open to answer any question…

Smarter Virtual Host Configuration on Windows

Sometimes our QA and Designer colleagues feels irritate when they need to setup some sites locally to test or fix design issues. Same thing for developers also. For setting up a new site we need to go through 4/5 steps. How about if we can reduce these steps into one?

Yeah, we can reduce these steps into one step. Just put your project folder maintaining an easy convention and you are done.

For example: you want to setup a site in your local machine with the following URL:
http://domain.local
Then the folder structure will be
local
    |
    --> domain

that’s it..

I found that Apache supports VirtualDocumentRoot, which give us some dynamic document root. Let, see how we can use this to achieve an smarter way to setup a site locally very easily. Before going ahead I just want to take a look on our OLD steps.

OLD Way: Setup a site for http://domain.local on your PC

  1. Create a directory for the site’s files.
  2. Create a line in hosts file for the domain, i.e. 127.0.0.1 domain.local
  3. Add a few lines to my Apache conf file to configure the virtual host

    <VirtualHost *:80>
        ServerName domain.local
        DocumentRoot D:\Projects\domain.local
        ...
    </VirtualHost>
  4. Restart Apache

But the New and Smarter way is

  1. Create a directory for the site’s files. Something like:
    D:\Projects\local\domain (for my case)

And you are done.. 😉

Now, for achieving this we have to do some configuration level changes for once.

  1. Edit your hosts file to add *.local domain in to host entry as bellow:

    127.0.0.1       localhost
    127.0.0.1       *.local
    ::1             localhost

  2. Enable vhost_alias_module modules/mod_vhost_alias.so in httpd.conf file (Apache configuration file). This will add VirtualDocumentRoot feature in the Apache.
    • usually you will find this file in [installed folder]\apache\conf\httpd.conf.
    • in this file find the above line and remove the preceding “#”.
  3. Now, go to {installed folder}\apache\conf\extra\ and edit httpd-vhosts.conf file as follows:

    NameVirtualHost *:80

    # Adding folder permissions
    <Directory "D:\Projects\local\*">
        Options Indexes FollowSymLinks
        AllowOverride All
        Order allow,deny
        Allow from all
        Require local
    </Directory>

    # Pointing folder for URLs.
    <VirtualHost *:80>
        UseCanonicalName Off     # This is a must.
        ServerAlias *.local
        VirtualDocumentRoot "D:\Projects\%-1\%-2"
    </VirtualHost>

  4. Restart your Apache service

So, Your configuration is done. This settings is only for .local URLs.

Now, to add a new site in local environment, just put your project folder in the local folder and browse with URL like http://{foldername}.local, cheers..

Here, ServerAlias *.local to limit to the .local URLs. You can add more pattern like ServerAlias *.local *.dev *.stg etc.

In VirtualDocumentRoot I used a dynamic URI to point the dynamic folder. The %-1 returns last part from the URLs (which is local for our case) and the %-2 returns the 2nd part of the URL from the last. I prefer this structure because this helps me when I want to point multiple URLs on a single folder. It can be for multi-site in Drupal CMS. For example: abc.xyz.local and aaa.xyz.local need to point on local\xyz folder.

You can use any pattern you like, Please refer here for more details of the URI pattern those are supported by Apache.

For any confusion or problem, please comment here or send me a message..

ExtJS: Horizontal sliding style paging for long panel [part-2]

In Part-1 I showed how we can use scrollBy(). In this part-2 we will see how we can do it with Position.

Panel Settings as before:

Ext.define('MyProj.view.AllPacksPanel', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.allpackspanel',
    title: 'All Packs',
    layout: 'hbox',
    id: 'allpackspanel',  //this is the ID we will use to get the component in button handler
    overflowX: 'scroll',  //horizontal scroll will be shown
    ...
    ...

Button with handler.

	dockedItems: [{
        xtype: 'toolbar',
        dock:'bottom',
        ui: 'footer',
        items: [
        {
            text: 'prev'
           iconCls: 'icon-prev'
           handler: function() {
               var cmp = Ext.getCmp("allpackspanel");
               var pos = cmp.getPosition();
               cmp.setPosition(pos[0]+300,pos[1],true);
           }
        },
        '->',
        {
            text: 'next'
           iconCls: 'icon-next'
           handler: function() {
               var cmp = Ext.getCmp("allpackspanel");
               var pos = cmp.getPosition();
               cmp.setPosition(pos[0]-300,pos[1],true);
           }
        }
        ]
    }]

The difference with scrollBy() in nothing at all. You may be noticed that both of this have the scroll bar is visible. If we Disable the scroll bar then this function will have no effect. But, seeing scroll bar is annoying. So We will see in Horizontal sliding style paging using jQuery how we can hide the scroll bar and make a smooth sliding like this.

ExtJS: Horizontal sliding style paging for long panel [part-1]

There are several ways to achieve Horizontal sliding style paging for a panel which is horizontally larger than window. Here in part-1 I will show how to use scrollBy() . For my case there are more than 20 Grid panel was added in a Panel. FYI: I used the MVC architecture of ExtJS.

I have added two button at bottom (Next and Prev) to move the scroll. So the code was like bellow:

Panel settings was:

Ext.define('MyProj.view.AllPacksPanel', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.allpackspanel',
    title: 'All Packs',
    layout: 'hbox',
    id: 'allpackspanel',  //this is the ID we will use to get the component in button handler
    overflowX: 'scroll',  //horizontal scroll will be shown
    ...
    ...

And code for button with handler:

    dockedItems: [{
        xtype: 'toolbar',
        dock:'bottom',
        ui: 'footer',
        items: [
        {
            text: 'prev'
           iconCls: 'icon-prev'
           handler: function() {
               var cmp = Ext.getCmp("allpackspanel");
               cmp.scrollBy(-300,0,true);
           }
        },
        '->',
        {
            text: 'next'
           iconCls: 'icon-next'
           handler: function() {
               var cmp = Ext.getCmp("allpackspanel");
               cmp.scrollBy(300,0,true);  //300 as I want it will scroll by inner inner grid where inner grid panel size is 300
           }
        }
        ]
    }]

We will see in Part-2 how we can do the same with the position.

How to use the “tilt” feature on an iphone

You can do this by accelerometer. Accelerometer will give you the value for x y z axis value when you tilt the device. to this add a property which is type of UIAccelerometer class.

    UIAccelerometer*  theAccelerometer;
	

now you define the frequency and the delegate. you should write this code from where you want to initiate receiving.

    theAccelerometer = [UIAccelerometer sharedAccelerometer];
    theAccelerometer.updateInterval = 1 / 50;
    theAccelerometer.delegate = self;
	

Now you have to add the delegation method

    -(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
        myX = acceleration.x;
        myY = acceleration.y;
        myZ = acceleration.z;
    }
	

Ok, now you have the value updated frequently at frequency 50 [means 20 mili second]. Now, if you want to stop receiving these values and obviously you should stop receiving if you leave this view and that will as follows:

    theAccelerometer.delegate = nil
	

Again you can start receiving accelerometer data again assigning the delegate to self

    theAccelerometer.delegate = self;
	

if you have any further question please feel free to contact.

Objective-C and sqlite’s DATETIME type

Well, I am sharing here just the core things regarding date formatting for saving and retrieving the data from Sqlite to Objective C or vice versa. If you have any problem with this code snippet then I will share the full code that I used for my project.

When you save your data, bind your date value in the sql statement like this way:

    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString *dateString=[dateFormat stringFromDate:[NSDate date];];

    sqlite3_bind_text(saveStmt, 1, [dateString UTF8String] , -1, SQLITE_TRANSIENT);
	

and when you retrieve data you have to write this code:

    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *myDate =[dateFormat dateFromString:[NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)]];
	

now you have a variable myDate of NSDate type which you can render in your way:

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"dd-MM-yyyy hh:mm:ss a"];
    NSLog(@"My Date was : %@", [formatter stringFromDate:myDate]);
	

You must have to remember 3 things:

  1. in your SQLite date field type should be DATETIME
  2. Date format should be same when you store and when you retrieve
  3. Now you can show in your won way but following the format. Bellow the format details has given.

Format:

    'dd' = Day 01-31
   'MM' = Month 01-12
   'yyyy' = Year 2000
   'HH' = Hour in 24 hour
   'hh' = Hour in 12 hour
   'mm' = Minute 00-59
   'ss' = Second 00-59
   'a' = AM / PM