Category Archives: Uncategorized

TDD Test AngularJs Service $Http

In my last post I have hardcode the data into the service to let my test pass, now in this post I will change that service to by inject the $http service into my module and let it return httpPromise.

Here is my new movieApi.js file


(function(){
   "use strict";
   
  var app =  angular.module('moviesApi',[]);

    app.factory('moviesApi',function($http, $q){
        var service = {};
        var baseUrl = 'http://www.omdbapi.com/?v=1&';

        function httpPromise (url) {
			var deferred = $q.defer();
			$http.get(url)
				.success(function(data) {
					deferred.resolve(data);
				})
				.error(function(error) {
					deferred.reject(error);
				});
			return deferred.promise;
		}

        service.search = function(query) {
			return httpPromise(baseUrl + 's=' + 
                               encodeURIComponent(query));
		} 
                    
   return service;
 });
})()

Then my unit test fail, that is because now my service return a promise and it has not resolve yet, but my test expect data, for how to solve this issue, angularjs has provide $httpBackend for Fake HTTP backend implementation for unit testing application that use the $http service.

Here is the new test code:

$httpBackend;
beforeEach(module('moviesApi'));
         //angular.mock is under the globe variable, so I have remove it 
         //the beforeEach is jasmine provide if you have multiple test need 
         //the same  set up, it will automatic set for each test, will reduce copy code
         //for name convenience  I also changed the service's name 
         //to match the module name
        //then in the dependence inject angularjs allow your put the underscore 
        //for your inject service,it will pick it up
	beforeEach(inject(function(_moviesApi_,_$httpBackend_) {
		moviesApi = _moviesApi_;
                $httpBackend = _$httpBackend_;
	}));
    
    it('should return search movies data',function(){
        var response;
        var expectedUrl = 'http://www.omdbapi.com/?v=1&s=star%20wars';
        $httpBackend.when('GET',expectedUrl)
                .respond(200,moviesData); 
        
        moviesApi.search('star wars')
                .then(function(data){
                        response = data;
                });

        //the fake $httpBackend has function flush will resolve the data for you to       //test

        $httpBackend.flush();

        expect(response).toEqual(moviesData);
    });

Tips: as frondend developer also could using this Fake data create a service response, so you do not need waiting for the backend service finished to do your job.

 

Now the test will pass.

Have fun!

Create angularjs service to let the test pass – to be continue…

Create angularjs service is very easy, in anguarjs 1.x have 4 way to create services, but the most of popular way is .factory, and I am going to use the factory function to create an angularjs service and let the angular-mock.js to inject this instance to my test and let my test pass.

In the real life project a lot of people put everything in one of angularjs module, but today we are going to follow  the TDD principle, I will follow the best practice way for write easy read and testable code. So I will create an separated angularjs module.

Here is the code part start:

Step1: create a folder named: services  under the src folder, and create moviesApi.js file, here is the code for that js file


(function(){
   "use strict";
   
  var app =  angular.module('moviesApi',[]);

    app.factory('moviesApi',function(){
        var service = {};
        service.search = function(query){
                                return {"Search":[{"Title":"Star Wars: Episode IV - A New Hope","Year":"1977","imdbID":"tt0076759","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BZGEzZTExMDEtNjg4OC00NjQxLTk5NTUtNjRkNjA3MmYwZjg1XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: Episode V - The Empire Strikes Back","Year":"1980","imdbID":"tt0080684","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BYmViY2M2MTYtY2MzOS00YjQ1LWIzYmEtOTBiNjhlMGM0NjZjXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode VI - Return of the Jedi","Year":"1983","imdbID":"tt0086190","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BODllZjg2YjUtNWEzNy00ZGY2LTgyZmQtYTkxNDYyOWM3OTUyXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: The Force Awakens","Year":"2015","imdbID":"tt2488496","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BOTAzODEzNDAzMl5BMl5BanBnXkFtZTgwMDU1MTgzNzE@._V1_SX300.jpg"},{"Title":"Star Wars: Episode I - The Phantom Menace","Year":"1999","imdbID":"tt0120915","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BM2FmZGIwMzAtZTBkMS00M2JiLTk2MDctM2FlNTQ2OWYwZDZkXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode III - Revenge of the Sith","Year":"2005","imdbID":"tt0121766","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNTc4MTc3NTQ5OF5BMl5BanBnXkFtZTcwOTg0NjI4NA@@._V1_SX300.jpg"},{"Title":"Star Wars: Episode II - Attack of the Clones","Year":"2002","imdbID":"tt0121765","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNDRkYzA4OGYtOTBjYy00YzFiLThhYmYtMWUzMDBmMmZkM2M3XkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008","imdbID":"tt1185834","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTI1MDIwMTczOV5BMl5BanBnXkFtZTcwNTI4MDE3MQ@@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008–2015","imdbID":"tt0458290","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTM0NjQ2Mjk0OV5BMl5BanBnXkFtZTcwODQ3Njc3Mg@@._V1_SX300.jpg"},{"Title":"Star Wars: Clone Wars","Year":"2003–2005","imdbID":"tt0361243","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMjE2Mjk5Mzk3M15BMl5BanBnXkFtZTcwMDkzMTIzMQ@@._V1_SX300.jpg"}],"totalResults":"354","Response":"True"};
                        };   

                   
                        
                    
   return service;

 });

})()

Now go back to your test spec file, using angular-mock to mock your module and inject the service:


angular.mock.module('moviesApi');//mock the module 
angular.mock.inject(function(_moviesApi_){//inject your real servies
            service = _moviesApi_;
        });


The movies.services.js should look like this:


describe('data services',function(){
    var moviesData = {"Search":[{"Title":"Star Wars: Episode IV - A New Hope","Year":"1977","imdbID":"tt0076759","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BZGEzZTExMDEtNjg4OC00NjQxLTk5NTUtNjRkNjA3MmYwZjg1XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: Episode V - The Empire Strikes Back","Year":"1980","imdbID":"tt0080684","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BYmViY2M2MTYtY2MzOS00YjQ1LWIzYmEtOTBiNjhlMGM0NjZjXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode VI - Return of the Jedi","Year":"1983","imdbID":"tt0086190","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BODllZjg2YjUtNWEzNy00ZGY2LTgyZmQtYTkxNDYyOWM3OTUyXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: The Force Awakens","Year":"2015","imdbID":"tt2488496","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BOTAzODEzNDAzMl5BMl5BanBnXkFtZTgwMDU1MTgzNzE@._V1_SX300.jpg"},{"Title":"Star Wars: Episode I - The Phantom Menace","Year":"1999","imdbID":"tt0120915","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BM2FmZGIwMzAtZTBkMS00M2JiLTk2MDctM2FlNTQ2OWYwZDZkXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode III - Revenge of the Sith","Year":"2005","imdbID":"tt0121766","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNTc4MTc3NTQ5OF5BMl5BanBnXkFtZTcwOTg0NjI4NA@@._V1_SX300.jpg"},{"Title":"Star Wars: Episode II - Attack of the Clones","Year":"2002","imdbID":"tt0121765","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNDRkYzA4OGYtOTBjYy00YzFiLThhYmYtMWUzMDBmMmZkM2M3XkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008","imdbID":"tt1185834","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTI1MDIwMTczOV5BMl5BanBnXkFtZTcwNTI4MDE3MQ@@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008–2015","imdbID":"tt0458290","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTM0NjQ2Mjk0OV5BMl5BanBnXkFtZTcwODQ3Njc3Mg@@._V1_SX300.jpg"},{"Title":"Star Wars: Clone Wars","Year":"2003–2005","imdbID":"tt0361243","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMjE2Mjk5Mzk3M15BMl5BanBnXkFtZTcwMDkzMTIzMQ@@._V1_SX300.jpg"}],"totalResults":"354","Response":"True"};

    it('should return search movies data',function(){
        var service = {};

        angular.mock.module('moviesApi');


        angular.mock.inject(function(_moviesApi_){
            service = _moviesApi_;
        })

        expect(service.search('star wars')).toEqual(moviesData);
    })
});

Now your test will be pass.

But still the moviesApi.js I hardcode the data over there, it is not what I want, next post, I will write code how to do HTTP test.

To be continue…

TDD AngularJs Services Test- continue with last post

Currently a lot of developer team like follow by the TDD pattern, it means that write your test first then write the code to let it pass.

Any app either is for display data or just for possessing data, so my first test that I lik to build the data services first. And know we need follow the TDD principle, so we need to create the test first.

Continue with my last post, then I create a folder name services under the spec folder and create a movies.services.spec.js.

Now  here is my first test:


describe('data services',function(){
    var moviesData = {"Search":[{"Title":"Star Wars: Episode IV - A New Hope","Year":"1977","imdbID":"tt0076759","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BZGEzZTExMDEtNjg4OC00NjQxLTk5NTUtNjRkNjA3MmYwZjg1XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: Episode V - The Empire Strikes Back","Year":"1980","imdbID":"tt0080684","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BYmViY2M2MTYtY2MzOS00YjQ1LWIzYmEtOTBiNjhlMGM0NjZjXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode VI - Return of the Jedi","Year":"1983","imdbID":"tt0086190","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BODllZjg2YjUtNWEzNy00ZGY2LTgyZmQtYTkxNDYyOWM3OTUyXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: The Force Awakens","Year":"2015","imdbID":"tt2488496","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BOTAzODEzNDAzMl5BMl5BanBnXkFtZTgwMDU1MTgzNzE@._V1_SX300.jpg"},{"Title":"Star Wars: Episode I - The Phantom Menace","Year":"1999","imdbID":"tt0120915","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BM2FmZGIwMzAtZTBkMS00M2JiLTk2MDctM2FlNTQ2OWYwZDZkXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode III - Revenge of the Sith","Year":"2005","imdbID":"tt0121766","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNTc4MTc3NTQ5OF5BMl5BanBnXkFtZTcwOTg0NjI4NA@@._V1_SX300.jpg"},{"Title":"Star Wars: Episode II - Attack of the Clones","Year":"2002","imdbID":"tt0121765","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNDRkYzA4OGYtOTBjYy00YzFiLThhYmYtMWUzMDBmMmZkM2M3XkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008","imdbID":"tt1185834","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTI1MDIwMTczOV5BMl5BanBnXkFtZTcwNTI4MDE3MQ@@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008–2015","imdbID":"tt0458290","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTM0NjQ2Mjk0OV5BMl5BanBnXkFtZTcwODQ3Njc3Mg@@._V1_SX300.jpg"},{"Title":"Star Wars: Clone Wars","Year":"2003–2005","imdbID":"tt0361243","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMjE2Mjk5Mzk3M15BMl5BanBnXkFtZTcwMDkzMTIzMQ@@._V1_SX300.jpg"}],"totalResults":"354","Response":"True"};

    it('should return search movies data',function(){
        var service = {};

        expect(service.search('star wars')).toEqual(moviesData);
    })
});

By the way, before I start I already run npm test, so you could see my test is fail.

firstfailexpect

So next we are going to write a code to let it pass.


describe('data services',function(){
    var moviesData = {"Search":[{"Title":"Star Wars: Episode IV - A New Hope","Year":"1977","imdbID":"tt0076759","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BZGEzZTExMDEtNjg4OC00NjQxLTk5NTUtNjRkNjA3MmYwZjg1XkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: Episode V - The Empire Strikes Back","Year":"1980","imdbID":"tt0080684","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BYmViY2M2MTYtY2MzOS00YjQ1LWIzYmEtOTBiNjhlMGM0NjZjXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode VI - Return of the Jedi","Year":"1983","imdbID":"tt0086190","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BODllZjg2YjUtNWEzNy00ZGY2LTgyZmQtYTkxNDYyOWM3OTUyXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Star Wars: The Force Awakens","Year":"2015","imdbID":"tt2488496","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BOTAzODEzNDAzMl5BMl5BanBnXkFtZTgwMDU1MTgzNzE@._V1_SX300.jpg"},{"Title":"Star Wars: Episode I - The Phantom Menace","Year":"1999","imdbID":"tt0120915","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BM2FmZGIwMzAtZTBkMS00M2JiLTk2MDctM2FlNTQ2OWYwZDZkXkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: Episode III - Revenge of the Sith","Year":"2005","imdbID":"tt0121766","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNTc4MTc3NTQ5OF5BMl5BanBnXkFtZTcwOTg0NjI4NA@@._V1_SX300.jpg"},{"Title":"Star Wars: Episode II - Attack of the Clones","Year":"2002","imdbID":"tt0121765","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BNDRkYzA4OGYtOTBjYy00YzFiLThhYmYtMWUzMDBmMmZkM2M3XkEyXkFqcGdeQXVyNDYyMDk5MTU@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008","imdbID":"tt1185834","Type":"movie","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTI1MDIwMTczOV5BMl5BanBnXkFtZTcwNTI4MDE3MQ@@._V1_SX300.jpg"},{"Title":"Star Wars: The Clone Wars","Year":"2008–2015","imdbID":"tt0458290","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTM0NjQ2Mjk0OV5BMl5BanBnXkFtZTcwODQ3Njc3Mg@@._V1_SX300.jpg"},{"Title":"Star Wars: Clone Wars","Year":"2003–2005","imdbID":"tt0361243","Type":"series","Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMjE2Mjk5Mzk3M15BMl5BanBnXkFtZTcwMDkzMTIzMQ@@._V1_SX300.jpg"}],"totalResults":"354","Response":"True"};

    it('should return search movies data',function(){
        var service = {};
        service.search = function (){
            return moviesData;
        }

        expect(service.search('star wars')).toEqual(moviesData);
    })
});
firstfailexpectpass

Now the test is passed, but this is not what we want, we want is an angularjs service instance.

That is my next post.  - to be continue...

 

Introduction Set up TTD for Angular App – to be continue

Step 1 : go to Jasmine release page https://github.com/jasmine/jasmine/releases download the standalone zip file.

Step2: create a project folder in your computer where you like to put it, unzip the jasmine standalone zip file inside your project folder, then we could delete the sample files inside src and spec folder since we won’t using it, but keep the folder, so we could still using it.

Step3:  run npm init (make sure nodejs has been install in your computer) will create package.json file

Step4: install karma as test runner

npm install karma --save-dev

Step5: install -g karma-cli

Step6: npm install karma-jasmine karma-chrome-launcher –save-dev

Step7:karma init (for add the config file for karma)

test

Step 8: normal running test in phantom is fast so also need install packages:

“karma-phantomjs-launcher”: “^0.2.1”,
“phantomjs”: “^1.9.18”

Now your package.json file will look like this


{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
     "test": "karma start karma.conf.js"
  },
  "keywords": [
    "sample"
  ],
  "author": "sandy zhang",
  "license": "ISC",
  "devDependencies": {
    "jasmine-core": "^2.3.4",
    "karma": "^0.13.9",
    "karma-chrome-launcher": "^0.2.0",
    "karma-jasmine": "^0.3.6",
    "karma-phantomjs-launcher": "^0.2.1",
    "phantomjs": "^1.9.18"
  }
}

Step9: Add angularjs and angular-mock.js into the lib folder, and included it into the karma config file


// Karma configuration
// Generated on Sat Nov 12 2016 22:15:24 GMT+1100 (AUS Eastern Daylight Time)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',


    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],


    // list of files / patterns to load in the browser
    files: [
      'lib/angular/angular.min.js',
      'lib/angular/angular-mocks.js',
      'src/**/*.js',
      'spec/**/*.js'
    ],


    // list of files to exclude
    exclude: [
    ],


    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },


    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],


    // web server port
    port: 9876,


    // enable / disable colors in the output (reporters and logs)
    colors: true,


    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,


    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantomJS'],


    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}

Now I create a calculater.js file inside src folder with one function

function add(x,y){
return x+y;
};

And create your first calculater.spec.js inside spec folder

describe(‘calculator’,function(){
it(‘should add two number’,function(){
expect(add(1,2)).toBe(3);
})
});

then run npm test, then your will get your result.

firsttest.JPG

 

Create your own style of Checkbox using css3

here it is my html

<input class=”purchase-list-item” name=”{{item}}” id=”{{item}}” type=”checkbox” value=””>
<label for=”{{item}}”></label>

for style it we first make the default input set it display none, then we change the style of it along with the label. here is the css:


input.purchase-list-item[type="checkbox"] {
    display: none;
}
input.purchase-list-item[type="checkbox"] + label:before {
    border: 1px solid #3C3E40;
    content: "\00a0";
    display: inline-block;
    font: 16px/1em sans-serif;
    height: 16px;
    margin: 0 .25em 0 0;
    padding: 0;
    vertical-align: top;
    width: 16px;
}
input.purchase-list-item[type="checkbox"]:checked + label:before {
    /*background: #3C3E40;*/
    color: #3C3E40;
    content: "\2713";
    text-align: center;
    font-weight:bold;
}

here it is the appearance:

customize_checkbox

React & ES6 project dev enviroment setup

In this day, the JavaScript project set up it was a big complex, and this tutorial will show you how to set up the environment for build react SPA working with ES6.

First, create package.json file, here is the common using packages I was included, and I will use npm start to run the project instead of gulp. so the packages has included the scripts part with in it.


{
  "name": "react-Demo",
  "version": "1.0.0",
  "description": "react kit for React and es6 demo project",
  "scripts": {
    "prestart":"babel-node tools/startMessage.js",
    "start":"npm-run-all --parallel test:watch open:src lint:watch",
    "open:src": "babel-node tools/srcServer.js",
    "lint": "node_modules/.bin/esw webpack.config.* src tools",
    "lint:watch": "npm run lint -- --watch",
    "test": "mocha --reporter progress tools/testSetup.js \"src/**/*.spec.js\"",
    "test:watch": "npm run test -- --watch"
  },
  "author": "Sandy Zhang",
  "license": "MIT",
  "dependencies": {
    "babel-polyfill": "6.8.0",
    "bootstrap": "3.3.6",
    "jquery": "2.2.3",
    "react": "15.0.2",
    "react-dom": "15.0.2",
    "react-redux": "4.4.5",
    "react-router": "2.4.0",
    "react-router-redux": "4.0.4",
    "redux": "3.5.2",
    "redux-thunk": "2.0.1",
    "toastr": "2.1.2"
  },
  "devDependencies": {
    "babel-cli": "6.8.0",
    "babel-core": "6.8.0",
    "babel-loader": "6.2.4",
    "babel-plugin-react-display-name": "2.0.0",
    "babel-preset-es2015": "6.6.0",
    "babel-preset-react": "6.5.0",
    "babel-preset-react-hmre": "1.1.1",
    "babel-register": "6.8.0",
    "colors": "1.1.2",
    "compression": "1.6.1",
    "cross-env": "1.0.7",
    "css-loader": "0.23.1",
    "enzyme": "2.2.0",
    "eslint": "2.9.0",
    "eslint-plugin-import": "1.6.1",
    "eslint-plugin-react": "5.0.1",
    "eslint-watch": "2.1.11",
    "eventsource-polyfill": "0.9.6",
    "expect": "1.19.0",
    "express": "4.13.4",
    "extract-text-webpack-plugin": "1.0.1",
    "file-loader": "0.8.5",
    "jsdom": "8.5.0",
    "mocha": "2.4.5",
    "nock": "8.0.0",
    "npm-run-all": "1.8.0",
    "open": "0.0.5",
    "react-addons-test-utils": "15.0.2",
    "redux-immutable-state-invariant": "1.2.3",
    "redux-mock-store": "1.0.2",
    "rimraf": "2.5.2",
    "style-loader": "0.13.1",
    "url-loader": "0.5.7",
    "webpack": "1.13.0",
    "webpack-dev-middleware": "1.6.1",
    "webpack-hot-middleware": "2.10.0"
  } 
}

step 2: setup the dev server with webpack, and for the developing tools all put it inside the tools folder.

  • in the root project create the webpack.config.dev.js, there are the standards

import webpack from 'webpack';
import path from 'path';

export default {
  debug: true,
  devtool: 'cheap-module-eval-source-map',
  noInfo: false,
  entry: [
    'eventsource-polyfill', // necessary for hot reloading with IE
    'webpack-hot-middleware/client?reload=true', //note that it reloads the page if hot module reloading fails.
    './src/index'
  ],
  target: 'web',
  output: {
    path: __dirname + '/dist', // Note: Physical files are only output by the production build task `npm run build`.
    publicPath: '/',
    filename: 'bundle.js' 
  },
  devServer: {
    contentBase: './src' //the folder put the source files
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),//for the hot load
    new webpack.NoErrorsPlugin()
  ],
  module: {
    loaders: [
      {test: /\.js$/, include: path.join(__dirname, 'src'), loaders: ['babel']},
      {test: /(\.css)$/, loaders: ['style', 'css']},
      {test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file"},
      {test: /\.(woff|woff2)$/, loader: "url?prefix=font/&limit=5000"},
      {test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream"},
      {test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml"}
    ]
  }
};

        

step 3: create a file named srcServer.js inside the tools, npm scripts already has the command will run to open the dev server.

 
import express from 'express';
import webpack from 'webpack';
import path from 'path';
import config from '../webpack.config.dev';
import open from 'open';

/* eslint-disable no-console */

const port = 3000;
const app = express();
const compiler = webpack(config);

app.use(require('webpack-dev-middleware')(compiler, {
  noInfo: true,
  publicPath: config.output.publicPath
}));

app.use(require('webpack-hot-middleware')(compiler));

app.get('*', function(req, res) {
  res.sendFile(path.join( __dirname, '../src/index.html'));
});

app.listen(port, function(err) {
  if (err) {
    console.log(err);
  } else {
    open(`http://localhost:${port}`);
  }
});

step 4: for people like to set up testing driver developer, create a testSetp.js inside the tools folder:


process.env.NODE_ENV = 'test';

require('babel-register')();

require.extensions['.css'] = function () {return null;};
require.extensions['.png'] = function () {return null;};
require.extensions['.jpg'] = function () {return null;};

var jsdom = require('jsdom').jsdom;

var exposedProperties = ['window', 'navigator', 'document'];

global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
  if (typeof global[property] === 'undefined') {
    exposedProperties.push(property);
    global[property] = document.defaultView[property];
  }
});

global.navigator = {
  userAgent: 'node.js'
};

documentRef = document; 

in the script I have

  "test": "mocha --reporter progress tools/testSetup.js \"src/**/*.spec.js\"",

will run with it.

step 5: setup the .babelrc in the root project

{
  "presets": ["react", "es2015"],
  "env": {
    "development": {
      "presets": ["react-hmre"]
    }
  }
}

step 6 : setup .eslintrc inside the root project


{
  "extends": [
    "eslint:recommended",
    "plugin:import/errors",
    "plugin:import/warnings"
  ],
  "plugins": [
    "react"
  ],
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "env": {
    "es6": true,
    "browser": true,
    "node": true,
    "jquery": true,
    "mocha": true
  },
  "rules": {
    "quotes": 0,
    "no-console": 1,
    "no-debugger": 1,
    "no-var": 1,
    "semi": [1, "always"],
    "no-trailing-spaces": 0,
    "eol-last": 0,
    "no-unused-vars": 0,
    "no-underscore-dangle": 0,
    "no-alert": 0,
    "no-lone-blocks": 0,
    "jsx-quotes": 1,
    "react/display-name": [ 1, {"ignoreTranspilerName": false }],
    "react/forbid-prop-types": [1, {"forbid": ["any"]}],
    "react/jsx-boolean-value": 1,
    "react/jsx-closing-bracket-location": 0,
    "react/jsx-curly-spacing": 1,
    "react/jsx-indent-props": 0,
    "react/jsx-key": 1,
    "react/jsx-max-props-per-line": 0,
    "react/jsx-no-bind": 1,
    "react/jsx-no-duplicate-props": 1,
    "react/jsx-no-literals": 0,
    "react/jsx-no-undef": 1,
    "react/jsx-pascal-case": 1,
    "react/jsx-sort-prop-types": 0,
    "react/jsx-sort-props": 0,
    "react/jsx-uses-react": 1,
    "react/jsx-uses-vars": 1,
    "react/no-danger": 1,
    "react/no-did-mount-set-state": 1,
    "react/no-did-update-set-state": 1,
    "react/no-direct-mutation-state": 1,
    "react/no-multi-comp": 1,
    "react/no-set-state": 0,
    "react/no-unknown-property": 1,
    "react/prefer-es6-class": 1,
    "react/prop-types": 1,
    "react/react-in-jsx-scope": 1,
    "react/require-extension": 1,
    "react/self-closing-comp": 1,
    "react/sort-comp": 1,
    "react/wrap-multilines": 1
  }
}

there are already have script command could run check the lint


 "lint": "node_modules/.bin/esw webpack.config.* src tools",

Now could start create react components
> create index.html inside the src folder

<!DOCTYPE html>
<html lang=”en”>
<head>
<title>Pluralsight Admin</title>
</head>
<body>

/bundle.js
</body>
</html>

create index.js file


/*eslint-disable import/default */
import 'babel-polyfill';
import React from 'react';
import { render } from 'react-dom';
import { Router, browserHistory } from 'react-router';
import routes from './routes';
import './styles/styles.css'; //Webpack can import CSS files too!
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';


render( 
    ,
  document.getElementById('app')
);

create route.js inside the src folder


import React from 'react';
import { Route, IndexRoute } from 'react-router';
import App from './components/App';
import HomePage from './components/home/HomePage';
import AboutPage from './components/about/AboutPage';


export default (
  
    
    
  
);

create components folder inside the src, then create App.js inside it


// This component handles the App template used on every page.
import React, {PropTypes} from 'react';


class App extends React.Component {
  render() {
    return (

heading

{this.props.children}

); } } App.propTypes = { children: PropTypes.object.isRequired }; export default App;

separate pages by folder,create home, about folder

for HomePage.js


import React from 'react';
import {Link} from 'react-router';

class HomePage extends React.Component {
  render() {
    return (

React Demo

React, Redux and React Router in ES6 for ultra-responsive web apps.

Learn more

); } } export default HomePage;

for AboutPage.js


import React from 'react';

class AboutPage extends React.Component {
  render() {
    return (

About

This application uses React, Redux, React Router and a variety of other helpful libraries.

 

); } } export default AboutPage;

source code here:

https://github.com/sandywebdesigner/react_es6_starter_demo

now run npm start it will open the page in the brower, and you could start code now. have fun!

the default page will look like this:

react_starter

Angularjs directive

Directives are the most important feature of AngularJS . Before we jump into how to create custom directive, first to understand the relationship between directive Scope and controllers is very important to help your create custom directives.

In angularjs, directive sit inside controllers, so when you create a custom directive, you must first create an angularjs module and controller first.

When you create a directive, angularjs provide 3 different scope for your to use:

Shared scope when you create a directive don’t specify the scope then it will be shared scope.So your controller and your directive has the same scope, like in c# field, the controller and the directive have point it point to the same object.Create shared scope you must be very careful, because the directive could override the controller scopes.

//shared scope example
angular.module('app', []);

angular.module('app').controller('mainCtrl', function($scope) {
  $scope.Todo = {
    title: 'your title',
    address: 'your address',
    description: 'your description'

});

angular.module('app').directive('toDoList', function() {
  return {// in here I didn't specify the scope, so it will be shared scope
    templateUrl: "todoList.html",
    restrict: "E"
  }
})

////event without define the scope in here, but the directive already share the 
//mainCtrol scope here
//toDolist.html
Title:{{title}}
Address:{{address}}
Description: {{description}}

Inherited scope when you create a directive return scope:true then it will create a inherited scope, so the parent scope(controller scope) will visible in the child scope( directive scope), but the  directive can’t override the parent scope. for example if you have scope.message = “parent message”; in the directive you create a scope.message = “child messages” it won’t override the parent scope, in there view if you use {{messages}} output is parent message, but if you use shared scope, in the directive template the output will be {{child messages}}

//shared scope example
angular.module('app', []);

angular.module('app').controller('mainCtrl', function($scope) {
  $scope.message = "parent message";
);

angular.module('app').directive('messagesView', function() {
  return {
    templateUrl: "messagesView.html",
    restrict: "E",
    scope:true,  // this is make the directive scope inherit from the mainCtrl
    controller:function($scope){
      $scope.message = "child message"; 

 } } })
//messagesView.html
{{message}} // output will be parent message 

Isolated scope: it allow the developer to encapsulate the data to your custom directive use only.

angular.module('app').directive('removeTodo', function() {
  return {
    restrict: 'E',
    templateUrl: 'removeTodo.html',
    scope: {
      todos: '=' //todos is only visible in your directive scope
    },
    controller: function($scope) {
      $scope.removeItem = function(todo) {
        var idx = $scope.data.indexOf(todo);
        if(idx > -1) {
          $scope.data.todo.splice(idx, 1);
        }
      }
      
    }
  }
})

And attach the whole angularjs directive structionangularjs-directive

Angularjs Service — Value and Constant Services

Value Services

  • Shorthand for factory with no parameters
  • Cannot be injected into a module configuration function
  • Can be overridden by an AngularJS decorator

Example using value

 angular.module('app')
        .value('clientId', 'a12345654321x');

Constant Services

  • Simply registers service with injector, no factory/provider calls
  • Can be injected into a module configuration function
  • Cannot be overridden by an AngularJSdecorator

Example

angular.module('app')
        .constant('constants', {
            APP_TITLE: 'My App',
            APP_DESCRIPTION: 'Description here.',
            APP_VERSION: '0.0.1'
        });

	

ANGULARJS SERVICES – Factory and Services

Using the factory function on the provide service is usually a much simpler option than using provider, if you don’t need to configure the underlying provider object. The snippet of code here is the Angular source code for the factory function.

function factory(name, factoryFn, enforce) { 
	return provider(name, { 
		$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn 
		}); 
	}

You can see that all it really does is call the provider function and assign the function you pass to the factory function as the value of the get property on the provider.

Internally, it creates and passes the parameter name, enforce, just as a safety check to make sure the function passed to it actually returns an object. To use the factory function, you just pass it a name as the first parameter, like the provider function, and the second parameter is a function that will return an object that represents the service instance. If you don’t need to configure the provider, like previous post sample demo code, then using the factory function will be a much simpler and readable way to create your services.

The next service creation function we’ll look at is actually named service. It’s just a very thin wrapper around the factory function we just saw. The only difference is that the function you passed to the service method will be treated as a constructor function and called with the JavaScript “new” operator.

The snippet here is the Angular source code for the service function.

	function service(name, constructor) { 
	  return factory(name, ['$injector', function($injector) {  
	   return $injector.instantiate(constructor); 
	   }]);
	 }

It uses the instantiate method of the injector to call the function you pass to the service method. The instantiate method will then use the “new” operator to execute the function that creates the service. You would use the service method instead of the factory method if you specifically needed your function to be treated as a constructor and called with the “new” operator. There are several reasons why you may want that behavior. One is if you have defined an inheritance hierarchy in your code. Creating an instance with “new” will make sure that your instantiated object properly inherits from its prototypes.

Here is the example you must use the services instead of factory.

angular.module('app')
        .service('logger', MyLogger);

    function LoggerBase() { }

    LoggerBase.prototype.output = function(message) {
        console.log('LoggerBase: ' + message);
    };

    function MyLogger() {

        LoggerBase.call(this);

        this.log = function(obj) {
            console.log('Book: ' + obj.name);
        }
    }

    MyLogger.prototype = Object.create(LoggerBase.prototype);

only now I can use the output function, but using factory it won’t.

 app.config(['$logProvider',  function ( $logProvider) {
        $logProvider.output('what ever here!');

to be continue……..