angular.js directory structure

.
├── app (all of the files to be used in production)
│   ├── main.html
│   ├── scripts
│   │   ├── app.js
│   │   ├── controllers
│   │   ├── services
│   │   ├── filters
│   │   └── directives
│   ├── modules (common modules coded by us)
│   ├── css
│   ├── images
│   ├── partials
│   |   └── login.html
│   ├── dist (any code made for production only. i.e. all.min.js)
│   └── vendor (3rd party scripts, i.e. jquery)
│       ├── angularjs
│       ├── bootstrap-3.0.2
│       └── leaflet-plugins
├── config (for test, doc, grunt, and package)
├── doc
├── test
|   ├── unit
|   └── regression
├── package.json (for development only)
├── Gruntfile.js (for development only)
└── node_modules (for development only)

D*** this kind of job posting..

The actual posting is here.

http://careers.stackoverflow.com/jobs/employer/Top%20Hathttp://careers.stackoverflow.com/jobs/employer/Top%20Hat

Looking for “Incredibly Smart Test Engineer ” ?
Looking for “Incredibly Smart Mobile Developer” ?

I am not looking for a job now but assuming I wanted to apply for a job to this company. I raise this question to myself

  • Am I INCREDIBLY Smart?

  • If so, what the f*** am I doing, reading this job posting? I must have a head-hunter agent and he/she does this reading, not me.

  • If I am actually INCREDIBLY Smart, I must be SUPER ARROGANT, like Sheldon in “Big Bang” series. Are they hiring weirdos and I have to work with them?

  • If not, and I want this job, I must lie to my self. Do they want employees who lie to themselves?

I wish this company just say “We are looking for a genius with IQ over 150”.

The Simplest LiveReload with Grunt

Livereload is very cool feature. It automatically watch file changes and notify to browser to update the page. So, you don’t need to refresh your page whenever update happens.

I can summarize it with two components;

  1. Server-side watcher and notifier
    This can be complete with
    1) livereload server($10)
    2) or, your own server watch and notify to browser using websocket

  2. Client-side message consumer
    This can be complete with
    1) livereload browser extension(or plugin)
    2) or, your own javascript to consume messages

As a programmer, I wanted to complete this feature with 2) and 2) both using my own script.

After two days of work, I was very close to rollout my version of livereload. However I figured out I can achieve this feature without any of my code, which means no maintenance.

The best programming is, no programing

To do so, you need to install the following node moduels

 $ npm install grunt-contrib-watch grunt-contrib-connect connect-livereload --save-dev     
  • grunt-contrib-watch is to monitor file changes and notify those to browsers using websocket with port 35729.

  • grunt-contrib-connect is to serve your files through http. You can also inject your own middleware

  • connect-livereload is the middleware used by grunt-contrib-connect to inject(add your your own script) to every single page.

The following is my gruntfile.js


module.exports = function (grunt) {

  // Load Grunt tasks declared in the package.json file
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
  
  grunt.initConfig({
   
    connect: {
      all : {
        options: {
          port: 9000,
          middleware: function(connect, options) {
            return [
              require('connect-livereload')({
                src: "//rawgithub.com/allenhwkim/util/master/livereload.js"
              }),
              connect.static('examples'), //http server base directory
              connect.directory('examples')  //allow directory browsing
            ];
          }
        }
      }
    },

    watch: {
      all: {
        files: ['app/**/*', 'examples/*'],
        options: {
          livereload: true  // starts livereload server at port 35729
        }
      }
    }

  });

  grunt.registerTask('server', ['connect', 'watch']);
};

It uses my own livereload.js file using websocket client. I have tried with the existing livereload.js with no luck, and I don’t need all the features provided from that anyway.

This is the code, you can find at https://github.com/allenhwkim/util/blob/master/livereload.js


/**
 * The following code will be injected every single page served by grunt-contrib-connect
 */
(function() {
  var ws = new WebSocket("ws://localhost:35729"); 
  ws.onmessage = function(msg) {
    console.log('received message', msg);
    if ((JSON.parse(msg.data)).command == "reload") {
      window.location.reload();
    }
  }; 
})();

Cheers

Google Map As The Simplest Way

I have been looking for a way to show a map on my site, but the even with the simplest solution, I found it requires Javascript coding.

Of course, I can code Javasript as a programmer. However, I don’t want to code. The best programming is no programming. If I can achieve my goal without any coding, that’s the best.

That’s the reason I created this, ng-map, AngularJS Google Maps Directive, I believe this is the simplest, simplest, and the simplest way to show a map on your page.

Thanks to AngularJS and its engineering team.

Let’s begin with this little tag. This will show a map with the current location.
<map />


The above is fully demonstrated here. As you see, there is NO single javascript required. It just needs AngularJS and ng-map.min.js to be loaded.

The above shows my current location, but I want to see “The statue of liberty” instead.
<map center=”the statue of liberty” />


It shows little slow, because it needs to get latitude and longitude from your vague input, I want to see it right away with the detailed map.
<map center=”[40.6892,-74.0444]” zoom=”18” />


How about satellite view? No problem.
<map center=”[40.6892,-74.0444]” zoom=”15” map-type-id=”MapTypeId.SATELLITE” />


I want the statue of liberty pin-pointed. Then, let’s add a marker.
<map center=”[38.89,-77.03]” zoom=”15” map-type-id=”MapTypeId.SATELLITE”>
  <marker position=”[40.6892,-74.0444]” />
</map>


How about bird eyes view?
<map center=”[40.6892,-74.0444]” zoom=”18” map-type-id=”MapTypeId.SATELLITE” tilt=”45” />


How about? ummm…, street view?
<map id="sv" street-view="StreetViewPanorama(document.querySelector('map#sv'), {position:new google.maps.LatLng(40.688738,-74.043871)})" />


Well, that’s a bit. Many would say why didn’t I make those javascript simpler like this, <map street-view=”selector:40.688738,-74.043871” />.

It looks easy for you at the beginning with that way, but it requires you to learn my own style, which I don’t want. I want you to learn nothing but Google Maps API only.

I would rather leave it as it is because that’s how Google Maps API syntax looks like,

Let’s go further. How about bird-dyes view and streetview together?
<map center="[40.6892,-74.0444]" zoom="18"
  map-type-id="MapTypeId.SATELLITE" tilt="45"
  street-view="StreetViewPanorama(document.querySelector('div#sv'), 
    {position:new google.maps.LatLng(40.688738,-74.043871)})"/>
<div id="sv" />


So far, you haven’t done any scripting, have you?

There are a lot more than I just mentioned here. Moreover, you can have full feature of Google Maps with this directive, and you just simply follow Google Maps v3 API documents and tutorials, not my directive documents and tutorials. In fact, there is any documentation or tutorial for this directive except github README file. "It’s That Simple".

For the full code and details, github is there.

GoogleMap AngularJS Directive, ng-map

I created a google maps angularjs directive, https://github.com/allenhwkm/angularjs-google-maps. This does not require any Javascript coding for simple functionality as I said ealier the best programming is no programming

To Get Started

One. Download and include ng-map.js or ng-map.min.js

    <script src="dist/ng-map.min.js"></script>`
  

Two. use map tag, and optionally, control, marker, and shape tags


    <map zoom="11" center="[40.74, -74.18]">
      <marker position="[40.74, -74.18]" />
      <shape name="circle" radius="400" center="[40.74,-74.18]" radius="4000" />
      <control name="overviewMap" opened="true" />
    </map>`  
 

Examples

To use it in your app, please include ‘ngMap’ as dependency to your app.

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

For more info, please visit github.

Service, Factory, and Provider, What’s difference?

From document,

An Angular “service” is a singleton object created by a “service factory”. These service factories are functions which, in turn, are created by a “service provider”. “The service providers are constructor functions”. When instantiated they must contain a property called $get, which holds the service factory function.

Whaaaaaaat? Am I reading a thesis? It is very confusing.

With AngularJS, whenever I need data, I want to create an object with properties and methods. However, AngularJS satisfies this requirement in three different ways; service, factory, and provider.

So, what do I use, Service, Factory, or Provider?

I searched around for this answer, and I wasn’t quite satisfied with the following answers, even with the accepted answer for this question.

It all says how it is different, but why?

The following is a real world example made up for this question, why.

  • Car itself is just a concept. AngularJS call it as service
  • A car is provided by a dealer,
  • A car is made at a factory.

Service, Factory, and Provider can be the same.

From the following example, you will get concept of a car, not a car with 4 cylinders.

app.service('CarService', function() {
    this.numCylinder = 4;
});

app.factory('CarFactory', function() {
    return {
        numCylinder: 4
    };
});

app.provider('CarProvider', function() {
    this.$get = function() {
        return {
            numCylinder: 4
        }
    };
});

Demo: http://plnkr.co/edit/nJmPbgxARLR3hoJwXUET?p=preview

They all gives you the same result.
Then you may think, then why do I need a factory and provider?
To get a different car, you cannot do it with just Service. You need Factory or Provider

To instantiate, you need Factory or Provider

How about I get 6-cylinders car, and you get 8-cylinders car?
With service(a singleton), you cannot achieve this because service cannot be instantiated.

app.service('CarService', function() {
    this.numCylinder = 4;
});

app.factory('CarFactory', function() {
    return function(numCylinder) {
        this.numCylinder = numCylinder
    };
});

app.provider('CarProvider', function() {
    this.$get = function() {
        return function(numCylinder) {
            this.numCylinder = numCylinder
        }
    };
});

Demo: http://plnkr.co/edit/Axszeuoa0XOOK1XOq0It?p=preview

As you see in the demo, and you will see my car and your car can actually have different number of cylinders.

That’s good enough for you?

Assuming there is one dealer for cars that you and I have and it is “BAD” one, you and I want to change(set) it as “GOOD” one. How can we set this dealer to the application by telling it only once?

  1. With service, we cannot do that because service just provide the concept of car
  2. With factory, yes we can by passing the dealer as a parameter every time we instantiate it. That’s not DRY.
  3. With provider, yes we can by setting the dealer only once, but how?

Provider can be configured for your application

This is how to implement setting the dealer of all cars.

app.service('CarService', function() {
   this.delaer="Bad";
    this.numCylinder = 4;
});

app.factory('CarFactory', function() {
    return function(numCylinder) {
      this.delaer="Bad";
        this.numCylinder = numCylinder
    };
});

app.provider('CarProvider', function() {
    this.dealerName = 'Bad';
    this.$get = function() {
        return function(numCylinder) {
            this.numCylinder = numCylinder;
            this.dealer = this.dealerName;
        }
    };
    this.setDealerName = function(str) {
      this.dealerName = str;
    }      
});

The following demo shows that we all have bad dealers

Demo: http://plnkr.co/edit/NdX1bZuYTG3371QBR5lX?p=preview

The following demo shows that we can configure the dealer.

app.config(function(CarProviderProvider) { 
  CarProviderProvider.setDealerName('Good');
});

Demo: http://plnkr.co/edit/UDzRruJGVAHBkovf0OPT?p=preview

But, why CarProviderProviderinstead of CarProvider?
Because app.config only takes providers to be injected nothing else, therefore when you say

app.config(function(CarProvider) { 
    ....
});

It actually looks up CarProviderProvider, CarProvider plus Provider.

For coding of provider, when you say

app.provider('Car', function....) {
    ....
});

It makes Car and CarProvider available for your application.

So when you say app.provider(CarProvider...), it actually makesCarProvideras service andCarProviderProvider` as provider. It’s not good, eh?

That’s why you see a lot of AngularJS code has a service and a provider at the same time. For an example, $route and $routeProvider, $http and $httpProvider, $location and $locationProvider, etc. As you see in API Reference, http://docs.angularjs.org/api/, all of AngularJS service is coded as a Provider, even $window.

The following demo. show the right way to define a provider.

Demo: http://plnkr.co/edit/ia5b1OcyBD5piP7q8ATr?p=preview

In conclusion,

---------------------------------------------------  
| Type    | Singleton| Instantiable | Configurable|
---------------------------------------------------  
| Service | Yes      | No           | No          |
---------------------------------------------------  
| Factory | Yes      | Yes          | No          |
---------------------------------------------------  
| Provider| Yes      | Yes          | Yes         |       
---------------------------------------------------  


  1. Use Service when you need just a simple object such as a Hash, for example {foo;1, bar:2} It’s easy to code, but you cannot instantiate it.

  2. Use Factory when you need to instantiate an object, i.e new Customer(), new Comment(), etc.

  3. Use Provider when you need to configure it. i.e. test url, QA url, production url.

Personally, I would use provider all the time so that I don’t have to change my code when I need to instantiate objects and when I need to configure it.

To start at ease and if you are not comfortable with this.$get = function().., I would say there is nothing wrong with to go with Service first.

My Wiki, Client-Side(angularjs/pagedown)

To follow “My Wiki, Server-Side”, This is the client-side html code.

The directory structure that I have for this server and client is;

server +— server.js client +— index.html

To start the server, you can simply run ‘node server.js’

<!doctype html>
<html ng-app="app">
<head>
<style>
  .markdown, .preview {box-sizing:border-box; float:left; width: 48%}
  textarea {width: 95%; height:400px}
  form input.ng-invalid.ng-dirty { background-color: #FA787E; }
  form input.ng-valid.ng-dirty { background-color: #78FA89; }
</style>
</head>
<body>
<div ng-view></div>

<script src="http://code.angularjs.org/1.2.3/angular.min.js"></script>
<script src="http://code.angularjs.org/1.2.3/angular-sanitize.min.js"></script>
<script src="http://code.angularjs.org/1.2.3/angular-route.min.js"></script>
<script src="http://code.angularjs.org/1.2.3/angular-resource.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Converter.js"></script>
<script type="text/ng-template" id="edit.html">
  <form novalidate name="form">
    <div>
      Title: <input ng-model="data.name" name="name" required /> <br/>
      Description: <input ng-model="data.description" name="description" required /><br/>
    </div>
    <div class="markdown">
      Body: <br/>
      <textarea ng-model="data.markdown" name="markdown" required></textarea>
      <br/>
      <button ng-disabled="!form.$valid" ng-click="save()">Save</button>
      <a ng-href="#/pages">pages</a>
    </div>
  </form>

  <div class="preview">
    <h3>Preview</h3>
    <div markdown-previewer markdown="data.markdown"></div>
  </div>
</script>
<script type="text/ng-template" id="index.html">
  <h1>List of Pages</h1>
  <a href="#/pages/new">Create New</a>
  <table>
    <tr><th>name</th><th>description</th><th>Actions</th></tr>
    <tr ng-repeat="page in data">
      <td>{{page.name}}</td>
      <td>{{page.description}}</td>
      <td>
        <a href="" ng-click="edit($index)">Edit</a>
        <a href="" ng-click="remove($index)">Remove</a>
      </td>
    </tr>
  </table>
</script>


<script>
var app = angular.module('app', ['ngSanitize', 'ngResource', 'ngRoute']);

app.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/pages', {
    templateUrl: 'index.html',
    controller: 'PagesController',
    resolve: {
      data: function($route, Page) {
        return Page.query($route.current.params).$promise;
      }
    }
  }).when('/pages/new', {
    templateUrl: 'edit.html',
    controller: 'PagesController',
    resolve: {
      data: function(Page) { return new Page(); }
    }
  }).when('/pages/:id', {
    templateUrl: 'edit.html',
    controller: 'PagesController',
    resolve: {
      data: function($route, Page) {
        return Page.get({id: $route.current.params.id}).$promise;
      }
    }
  }).otherwise({
    redirectTo: '/pages'
  });
}]);

app.directive('markdownPreviewer', function () {
  var converter = new Markdown.Converter();
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      scope.$watch(attrs.markdown,    function() { 
        element.html(converter.makeHtml(eval('scope.'+attrs.markdown)||''));
      });
    }
  };
})

app.factory('Page', function($resource) {
  return $resource('http://localhost:8888/pages/:id', {id: '@_id'}, {
    update: { method: 'PUT' }
  });
});

app.controller('PagesController', function($scope, $route, $sce, $window, $location, data) {
  $scope.data = data;
  $scope.save = function() {
    if (data._id) {
      data.$update();
      $location.path('/pages/'+data._id);
    } else {
      data.$save();
      $location.path("/pages");
    }
  }
  $scope.edit = function($index) {
    $location.path('/pages/'+data[$index]._id);
  }
  $scope.remove = function($index) {
    if ($window.confirm('Are You Sure?')) {
      data[$index].$remove(function() {
        $route.reload();
      });
    };
  }
});
</script>
</body>
</html>

My wiki, Server-side (nodejs/restify/mongodb)

In addition to “The Simplest RESTful server with nodejs, restify, and mongodb”, I am going to add another server-side script with schema.

It gets simpler when you use schema, but you need to stick to the schema.

The following code is to be used on the server-side of my simple wiki.


var restify = require('restify'),   // RESTful API Web Server
    mongoose = require('mongoose'); // mongodb connection

/**
 * config server
 */
var server = restify.createServer();
server.use(restify.fullResponse()); // enable default headers
server.use(restify.bodyParser());   // remap body contentnt of a request to the req.params
server.use(restify.queryParser());  // remap query string to req.params

/**
 * config database(wiki) and model(Page) with collection(pages)
 */
mongoose.connect('mongodb://localhost/wiki');
var db = mongoose.connection;
db.on('error', function()  { console.error('connection error:');} );
db.once('open', function() { console.log('connected to database');} );
var PageSchema = mongoose.Schema({
  name:  String,
  description: String,
  markdown:  String
});
var Page = mongoose.model('pages', PageSchema);

// curl -X GET http://localhost:8888/pages?name=foo
server.get('/pages', function(req, res, next) {
    Page.find(req.params, function(err, pages) {
        if(err) res.send(500, {error: err});
        else    res.send(200, pages);
        return next();
    });
    return next();
});

// curl -X GET http://localhost:8888/pages/51
server.get('/pages/:id', function(req, res, next) {
    Page.findById(req.params.id, function(err, page) {
        if(err || !page) res.send(404, {error: err||'Not Found'});
        else             res.send(200, page);
        return next();
    });
});

// curl -X POST http://localhost:8888/pages -d "name=new" -d"desc=foo"
server.post('/pages', function(req, res, next) {
    (new Page(req.params)).save(function (err, new_page) {
        if(err) res.send(500, {error: err});
        else    res.send(201, 'created');
        return next();
    });
});

// curl -X POST http://localhost:8888/pages/:id --d "name=Changed"
server.put('/pages/:id', function(req, res, next) {
    delete req.params._id;
    Page.findByIdAndUpdate(req.params.id, req.params, function (err, updated_page) {
        if(err) res.send(500, {error: err});
        else    res.send(200, updated_page);
    });
    return next();
});

// curl -X DELETE http://localhost:8888/pages/51
server.del('/pages/:id', function(req, res, next) {
    Page.findByIdAndRemove(req.params.id, function (err) {
        if(err) res.send(500, {error: err});
        else    res.send(204, 'Removed');
    });
    return next();
});

//The default get request matching
server.get(/\/?.*/, restify.serveStatic({
  'directory': __dirname+'/../client',
  'default': 'index.html'
}));

server.listen(8888, function() {
    console.log('% listening at %s', server.name, server.url);
});

Markdown meets AngularJS

Can be very SIMPLY done with;

  1. angular-sanitize.min.js
  2. Markdown.Converter.js
  3. ng-bind-html

This is in action
http://plnkr.co/edit/rPn46wgCX7GjFaEaiWtM?p=preview


<!doctype html>
<html ng-app="myApp">
<head>
<style>
  .markdown, .preview {box-sizing:border-box; float:left; width: 48%}
  textarea {width: 95%; height:600px}
</style>
</head>
<body>
<div ng-controller="PagedownController">
  <div class="markdown">
    <h3>Enter Markdown Here</h3>
    <textarea name="markdown" ng-model="markdown"></textarea>
  </div>

  <div class="preview">
    <h3>Preview</h3>
    <div id="preview" ng-bind-html="converter.makeHtml(markdown)"></div>
  </div>
</div>
<script src="http://code.angularjs.org/1.2.3/angular.min.js"></script>
<script src="http://code.angularjs.org/1.2.3/angular-sanitize.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/pagedown/1.0/Markdown.Converter.js"></script>
<script>
var myApp = angular.module('myApp', ['ngSanitize']);
function PagedownController($scope, $sce) {
    $scope.converter = new Markdown.Converter();
    $scope.markdown = "Enter *Your* [markdown](http://daringfireball.net/)";
}
</script>
</body>
</html>

The Simplest RESTful server with nodejs, restify, and mongodb

In addition to The Simplest RESTful server with nodejs and restify, this is the more practical solution, but still the simplest way to build nodejs, restify, and mongodb.

First, you need to setup mongodb database and insert data into it.

How To Install & Run MongoDB (Mac OS X)

$ brew update
$ brew install mongodb
$ mkdir -p ~/data/mongodb

$ mongod --fork --dbpath ~/data/mongodb/ --logpath /var/log/mongodb.log  # START
$ mongo --eval "db.shutdownServer()" admin                               # STOP

How To Import StarBucks Data To Your Mongodb

$ mongoimport -d starbucks -c stores --type csv --file starbucks_locations.csv --headerline
$ mongo  # to validate import
> show dbs
> use starbucks
> db.stores.find({"Store ID":1006099})

Starbucks store location data is found at https://opendata.socrata.com/Business/All-Starbucks-Locations-in-the-World/xy4y-c4mk

The following is the server code part. You may need to install mongoose npm install mongoose if you did not.


var restify = require('restify'),   // RESTful API Web Server
    mongoose = require('mongoose'); // mongodb connection

/**
 * config server
 */
var server = restify.createServer();
server.use(restify.fullResponse()); // enable default headers
server.use(restify.bodyParser());   // remap body contentnt of a request to the req.params
server.use(restify.queryParser());  // remap query string to req.params

/**
 * config database(starbucks) and model(Store) with collection(stores)
 */
mongoose.connect('mongodb://localhost/starbucks');
var db = mongoose.connection;
db.on('error', function()  { console.error('connection error:');} );
db.once('open', function() { console.log('connected to database');} );
// schemaless structure with no restriction to attributes
var StoreSchema = mongoose.Schema({any:{}}, {strict:false})
var Store = mongoose.model('stores', StoreSchema);

// $ curl -X GET http://localhost:8080/starbucks?country=AE
server.get('/starbucks', function(req, res, next) {
    var attrs = req.params;
    Store.find(req.params, function(err, stores) {
        if(err) res.send(500, {error: err});
        else    res.send(200, stores);
        return next();
    });
    return next();
});
// $ curl -X GET http://localhost:8080/starbucks/51
server.get('/starbucks/:id', function(req, res, next) {
    var storeId = parseInt(req.params.id);
    Store.findOne({"Store ID":storeId}, function(err, store) {
        if(err || !store) res.send(404, {error: err||'Not Found'});
        else              res.send(200, store);
        return next();
    });
});
// $ curl -X POST http://localhost:8080/starbucks -d "Store ID=1234567890" -d "Name=Test"
server.post('/starbucks', function(req, res, next) {
    req.params["Store ID"] = parseInt(req.params["Store ID"]);
    var store = new Store(req.params);
    store.save(function (err, store_saved) {
        if(err) res.send(500, {error: err});
        else    res.send(201, 'created');
        return next();
    });
});
// $ curl -X POST http://localhost:8080/starbucks/51 --d "Name=Changed"
server.put('/starbucks/:id', function(req, res, next) {
    var storeId = parseInt(req.params.id);
    delete req.params.id;
    Store.update({"Store ID":storeId}, req.params, function (err, store_saved) {
        if(err) res.send(500, {error: err});
        else    res.send(200, store_saved);
    });
    return next();
});
// $ curl -X DELETE http://localhost:8080/starbucks/51
server.del('/starbucks/:id', function(req, res, next) {
    var storeId = parseInt(req.params.id);
    Store.remove({"Store ID":storeId}, function (err) {
        if(err) res.send(500, {error: err});
        else    res.send(204, 'Removed');
    });
    return next();
});

server.listen(8080, function() {
    console.log('% listening at %s', server.name, server.url);
});

Happy Coding,