My studying notebook

2014/06/28

AngularJs, RequireJs, Grunt and Bower Part1 - Getting Started and concept with ASP.NET MVC (update:2014/7/16)

6/28/2014 01:20:00 PM Posted by Kai-Chu Chung , , , , , , , 3 comments

This article is part of a series of posts on RequireJs, AnguarJs, Grunt and Bower. Here are the parts so far:

  1. AngularJs, RequireJs, Grunt and Bower Part1 - Getting Started and concept with ASP.NET MVC.
  2. AngularJs, RequireJs, Grunt and Bower Part2 - Grunt
  3. AngularJs, RequireJs, Grunt and Bower Part3 - generator-angular-requirejs-grunt-bower with ASP.NET MVC
  4. AngularJs, RequireJs, Grunt and Bower Part4 - How to extend your own code with ASP.NET MVC
  5. AngularJs, RequireJs, Grunt and Bower Part5 - Yoeman generator-angular-requirejs-grunt-bower with Express.js //to be done

There are more and more fancy web applications. Developers have one same gold that they want their visitors have better user experience. So, they start working with heave JavaScript. (AngularJs, Backbone.js, Emberjs etc.).

There are dozen of awesome Javascript frameworks now, You can choose the suitable one for your project. In my company, we use ASP.NET MVC to develop web application. From ASP.NET MVC 2, 3, 4 to 5. I am looking a good practice to implement a good Javascript framework to my project till i meet AngularJs. AngularJs Javascript is top 10 Github repo until now and hosted by Google.

It’s very easy to use AngularJs in your web application page.

<!doctype html>
<html ng-app>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.13/angular.min.js"></script>
  </head>
  <body>
    <div>
      <label>Name:</label>
      <input type="text" ng-model="yourName" placeholder="Enter a name here">
      <hr>
      <h1>Hello {{yourName}}!</h1>
    </div>
  </body>
</html>

Above is a simple sample code from AngularJs official page. live demo here

MVVM concept and powerful two-way databinding can help you solve the problem you might working hard with jQuery. But for the large web application. Is a better way to integrate AngularJs in your project? YES, you can re-factor your code to module and include it to project.

// i define a ui.tiff module to hanle tiff viewer
angular.module('ui.tiff', ['ui.tiff.controller', 'ui.tiff.service', 'ui.tiff.directive', 'ui.tiff.filter']);
angular.module('ui.tiff.controller', []).controller('_aCtrl', ['$scope',
    function($scope) {
        ...
    }
]);

angular.module('ui.tiff.service', []).factory('ImageInfo', ['$resource',
    function($resource) {
        ...
    }
]);

angular.module('ui.tiff.directive', []).directive('tiffClick', [
    function() {
        ...
    }
]);

angular.module('ui.tiff.filter', []).filter('thumbnail', function() {
    ...
});

Concept

Be an ASP.NET MVC developer. How can we integrate APS.NET MVC with AngulaJs as well? ASP.NET MVC can render view page for each controller method. for example:

  • Views/Home/Index
  • Views/Home/About
  • Views/Management/Index

For Above route URL, we can get different ASP.NET MVC view page. But, i want to treat each of them as individual SPA (single page appliation) and share the same code (AngluarJs server or AngularJs filter modules etc.) for different SPA.

  • Views/Home/Index (SPA)
  • Views/Home/About (SPA)
  • Views/Home/Contact
  • Views/Management/Index (SPA)

Dan Wahlin has many awesome articles talk about ASP.NET MVC with AngularJs

Scenario

Yngve Bakken Nilsen has a awesome article talk about Making RequireJS play nice with ASP.NET MVC

RequireJs

In a heavey Javascript project. you might load more than 10 Javascript libraries easily. One of most important issues is to figure out Javascript library dependency and library synchronous loading. RequireJs is a JavaScript file and module loader.You can define library dependency (not worry which library should be loaded earlier than another one.) and avoid page loading block problem.

My solution is base on Yngve Bakken Nilsen article (RequierJs with ASP.NET MVC) but integrate with AngularJs, Grunt and Bower.

ASP.NET MVC File Structure

...
├── Controller
|   └── HomeController
├── Views
|   └── Home
|       ├── About.cshtml
|       ├── Contact.cshtml
|       └── Index.cshtml
├── Models
...

Above is ASP.NET MVC normal file structure. You can add NameController and assign view template views/ControllerName/ActionName to render view page. As i menetioned before, i’ll like to treat Views/Controler as SPA. so, i rearrange the basic file strcutre and put all of Javscript file in Public folder.

for the controller has more than one action view page. I move those page to front-end AngularJs framework. AngularJs route will handle this part.

AngularJs, RequireJs, Grunt and Bower OverView

RequireJs, AnguarJs, Grunt, Bower overview

Above diagram is whole project overview. RequireJs let us can include specific library we needed. All Javascript codes are put in Public folder.

...
Public
|   └── js
|   |   ├── controllers
|   |   |   ├── controllers.js
|   |   |   └── home-controller.js
|   |   ├── css
|   |   ├── directives
|   |   |   ├── directives.js
|   |   |   └── home-directive.js
|   |   ├── services
|   |   |   └── services.js
|   |   ├── vendor
|   |   ├── filters
|   |   |   ├── filters.js
|   |   |   └── common-filer.js
|   |   ├── views
|   |   |   ├── Management
|   |   |   |   ├── partials
|   |   |   |   |   └── management-index.html
|   |   |   |   └── index.js
|   |   |   └── Home
|   |   |       ├── partials
|   |   |       |   └── home-index.html
|   |   |       └── index.js
|   |   ├── app.js
|   |   └── config.js
|   └── release
Views
    ├── Management
    |   └── Index.cshtml    
    └── Home
        └── Index.cshtml    

As you can see the modified file structure. Public/js/views file structure like ASP.NET MVC Views. So, we could dynamic to load SPA by RequireJs if we have defined it in Public/js/views/mapping to ASP.NET MVC controller.

// Route: http://localhost/Home/Index
require( [ "/public/js/config.js" ], function() {
    require( [ "views/Home/Index" ] ); 
});

// Route: http://localhost/Account/Index
// no any AngularJs application will be loaded.
require( [ "/public/js/config.js" ], function() {
    require( [""] ); 
});

Angularjs Application

AngularJs, RequireJs concept

The basic concept is that i want to treat ASP.NET MVC route Views/ControllerName as a individual AngularJs SPA and Dynamic be loaded if i have defined it.

  • Define AngularJs module using RequireJs define.
  • Include needed module with RequireJs require.

I can define task orientation AngularJs module as you can see in above diagram. It’s easy to include specific controller, service, filter and direcitve that inherent from controllers/controllers, services/services, filters/filters and directives/directives in application. Put all together and bootstrap AngularJs application when DOM ready.

Everything looks so good but RequireJs config.js. I have to tell RequireJs the external libraries path and module name i include to the application. There are more information about RequireJs configuration in here.

require.config({
    baseUrl: "/public/js",
    waitSeconds: 200,
    paths: {
        'angular': 'vendor/angular/angular.min',
        'angular.zh-tw': 'vendor/angular-i18n/angular-locale_zh-tw',
        'angular.route': 'vendor/angular-route/angular-route.min',
        'angular.resource': 'vendor/angular-resource/angular-resource.min',
        'angular.animate': 'vendor/angular-animate/angular-animate.min',
        'angular.sanitize': 'vendor/angular-sanitize/angular-sanitize.min',
        'angular.cookies': 'vendor/angular-cookies/angular-cookies.min',

        'jquery': 'vendor/jquery/jquery.min',
        'moment': 'vendor/momentjs/min/moment.min',
        'respond': 'vendor/respond/dest/respond.src',
        'domReady': 'vendor/requirejs-domready/domReady',

        'bootstrap': 'vendor/bootstrap/dist/js/bootstrap.min',
        'uiBootstrap': 'vendor/angular-ui-bootstrap-bower/ui-bootstrap.min',
        'uiBootstrapTpl': 'vendor/angular-ui-bootstrap-bower/ui-bootstrap-tpls.min',
    },
    shim: {
        'moment': {
            exports: 'moment'
        },
        'angular': {
            deps: ['jquery', 'moment'],
            exports: 'angular'
        },
        'angular.zh-tw': ['angular'],
        'angular.route': ['angular'],
        'angular.resource': ['angular'],
        'angular.sanitize': ['angular'],
        'angular.animate': ['angular'],
        'angular.cookies': ['angular'],
        'respond': {
            exports: 'respond'
        },
        'bootstrap': {
            deps: ['jquery'],
            exports: 'bootstrap'
        },
        'uiBootstrap': {
            deps: ['angular', 'bootstrap'],
            exports: 'uiBootstrap'
        },
        'uiBootstrapTpl': {
            deps: ['angular', 'uiBootstrap']
        }
    },
    //urlArgs: "bust=" + (new Date()).getTime()
    urlArgs: "bust=v8"
});

It’s very convenient to integrate Bower package manager with your project. I put all of external libraries in vendor and save those library in bower.json. You can restore those libaries by execute command bower install

//bower.json
{
  "name": "application name",
  "version": "0.0.1",
  "dependencies": {},
  "devDependencies": {
    "angular": "~1.2.16",
    "requirejs-domready": "~2.0.1",
    "angular-route": "~1.2.16",
    "angular-resource": "~1.2.16",
    "angular-sanitize": "~1.2.16",
    "angular-cookies": "1.2.16",
    "momentjs": "~2.5.1",
    "angular-animate": "~1.2.16",
    "respond": "~1.4.2",
    "jquery": "1.10.2",
    "bootstrap": "~3.1.1",
    "angular-i18n": "~1.2.16",
    "angular-ui-bootstrap-bower": "~0.11.0",
    "moment": "~2.6.0"
  },
  "resolutions": {
    "angular": "~1.2.16"
  }
}

Intergrate with ASP.NET MVC

    ...
    var action = helper.ViewContext.RouteData.Values["action"];
    var controller = helper.ViewContext.RouteData.Values["controller"];
    string module = string.Format("views/{0}/{1}", controller, action);

    string jsLocation = "/public/js/";
    if (File.Exists(helper.ViewContext.HttpContext.Server.MapPath(Path.Combine(jsLocation, module + ".js"))))
    {
        require.AppendLine("require( [ \"" + jsLocation + core + "\" ], function() {");
        require.AppendLine("    require( [ \"" + module + "\"] );");
        require.AppendLine("});");
    }
    else
    {
        require.AppendLine("require( [ \"" + jsLocation + core + "\" ], function() {");
        require.AppendLine("    require( [ \"jquery\", \"bootstrap\" ] );");
        require.AppendLine("});");
    }
    ...

Final step. All you need to do is go Views/Shared/_Layout.cshtml and add @Html.ViewSpecificRequireJS() before body close tag. @Html.ViewSpecificRequireJS() is a ASP.NET MVC static method and it will read your project file structure. If you define an application in /public/js/view/Home and ASP.NET MVC route is mapping to views/controllerName. @Html.ViewSpecificRequireJS() static method will redener it, otherwise not. Don’t forget to include @Html.ViewSpecificRequireJS() Namespace @using Requirejs.Helpers in top of Views/Shared/_Layout.cshtml page.

you have to add <div ng-view></div> to thoes ASP.NET MVC views page for AngularJs route.

Preview

AngularJs, RequireJs concept

AngularJs, RequireJs concept

Reference

  1. Making RequireJS play nice with ASP.NET MVC by Yngve Bakken Nilsen
  2. RequireJS API config
  3. Bower Package manager
  4. Dan Wahlin - Dan Wahlin

Github Source Code

cage1016/AngularJsRequireJsGruntBower

After you clone source code from github repo, you can run following command:

  • git checkout -f step-0 is status project created
  • git checkout -f step-1 is status Nuget install Require.js.
  • git checkout -f step-2 is status project Add AngularJs, RequireJs, Grunt and Bower to Public folder.
  • git checkout -f step-3 is status modify _Layout.chtml to render RequireJs. You will see the final result.
    • Please cd to AngularJsRequireJsGruntBower\AngularJsRequireJsGruntBower\Public and execute bower install to restore those library project included.
  • git checkout -f setp-4 is status ready to do grunt tasks.
    • Please cd to AngularJsRequireJsGruntBower\AngularJsRequireJsGruntBower\Public and execute npm install to restore grunt required libraries.
    • execute command grunt to do grunt tasks.

2014/06/04

Welcome document

6/04/2014 09:07:00 PM Posted by Kai-Chu Chung No comments

Welcome to StackEdit!

this id d

Hello, I am your first Markdown document within StackEdit1. Don’t delete me, I can be helpful. I can be recovered anyway in the Utils tab of the Settings dialog.


Documents

StackEdit stores your documents in your browser, which means all your documents are automatically saved locally and are accessible offline!

NOTE:

  • StackEdit is accessible offline after the application has been loaded for the first time.
  • Your local documents are not shared between different browsers or computers.
  • Clearing your browser’s data may delete all your local documents! Make sure your documents are backed up using Google Drive or Dropbox synchronization (see Synchronization section).

Create a document

You can create a new document by clicking the button in the navigation bar. It will switch from the current document to the new one.

Switch to another document

You can list all your local documents and switch from one to another by clicking the button in the navigation bar.

Rename a document

You can rename the current document by clicking the document title in the navigation bar.

Delete a document

You can delete the current document by clicking the button in the navigation bar.

Save a document

You can save the current document to a file using the Save as... sub-menu from the menu.

Tip: See Publish a document section for a description of the different output formats.


Synchronization

StackEdit can be combined with Google Drive and Dropbox to have your documents centralized in the Cloud. The synchronization mechanism will take care of uploading your modifications or downloading the latest version of your documents.

NOTE:

  • Full access to Google Drive or Dropbox is required to be able to import any document in StackEdit.
  • Imported documents are downloaded in your browser and are not transmitted to a server.
  • If you experience problems exporting documents to Google Drive, check and optionally disable browser extensions, such as Disconnect.

Import a document

You can import a document from the Cloud by going to the Google Drive or the Dropbox sub-menu and by clicking Import from.... Once imported, your document will be automatically synchronized with the Google Drive / Dropbox file.

Export a document

You can export any document by going to the Google Drive or the Dropbox sub-menu and by clicking Export to.... Even if your document is already synchronized with Google Drive or Dropbox, you can export it to a another location. StackEdit can synchronize one document with multiple locations.

Tip: Using Google Drive, you can create collaborative documents to work in real time with other users. Just check the box Create a real time collaborative document in the dialog options when exporting to Google Drive.

Synchronize a document

Once your document is linked to a Google Drive or a Dropbox file, StackEdit will periodically (every 3 minutes) synchronize it by downloading/uploading any modification. Any conflict will be detected, and a local copy of your document will be created as a backup if necessary.

If you just have modified your document and you want to force the synchronization, click the button in the navigation bar.

NOTE: The button is disabled when you have no document to synchronize.

Manage document synchronization

Since one document can be synchronized with multiple locations, you can list and manage synchronized locations by clicking Manage synchronization in the menu. This will open a dialog box allowing you to add or remove synchronization links that are associated to your document.

NOTE: If you delete the file from Google Drive or from Dropbox, the document will no longer be synchronized with that location.


Publication

Once you are happy with your document, you can publish it on different websites directly from StackEdit. As for now, StackEdit can publish on Blogger, Dropbox, Gist, GitHub, Google Drive, Tumblr, WordPress and on any SSH server.

Publish a document

You can publish your document by going to the Publish on sub-menu and by choosing a website. In the dialog box, you can choose the publication format:

  • Markdown, to publish the Markdown text on a website that can interpret it (GitHub for instance),
  • HTML, to publish the document converted into HTML (on a blog for instance),
  • Template, to have a full control of the output.

NOTE: The default template is a simple webpage wrapping your document in HTML format. You can customize it in the Services tab of the Settings dialog.

Update a publication

After publishing, StackEdit will keep your document linked to that publish location so that you can update it easily. Once you have modified your document and you want to update your publication, click on the button in the navigation bar.

NOTE: The button is disabled when the document has not been published yet.

Manage document publication

Since one document can be published on multiple locations, you can list and manage publish locations by clicking Manage publication in the menu. This will open a dialog box allowing you to remove publication links that are associated to your document.

NOTE: In some cases, if the file has been removed from the website or the blog, the document will no longer be published on that location.


Markdown Extra

StackEdit supports Markdown Extra, which extends Markdown syntax with some nice features.

Tip: You can disable any Markdown Extra feature in the Extensions tab of the Settings dialog.

Tables

Markdown Extra has a special syntax for tables:

Item Value
Computer 1600 USD
Phone 12 USD
Pipe 1 USD

You can specify column alignment with one or two colons:

Item Value Qty
Computer 1600 USD 5
Phone 12 USD 12
Pipe 1 USD 234

Definition Lists

Markdown Extra has a special syntax for definition lists too:

Term 1
Term 2
Definition A
Definition B
Term 3

Definition C

Definition D

part of definition D

Fenced code blocks

GitHub’s fenced code blocks2 are also supported with Prettify syntax highlighting:

// Foo
var bar = 0;

Tip: To use Highlight.js instead of Prettify, just configure the Markdown Extra extension in the Settings dialog.

Footnotes

You can create footnotes like this3.

SmartyPants

SmartyPants converts ASCII punctuation characters into “smart” typographic punctuation HTML entities. For example:

ASCII HTML
Single backticks 'Isn't this fun?' ‘Isn’t this fun?’
Quotes "Isn't this fun?" “Isn’t this fun?”
Dashes -- is an en-dash and --- is an em-dash – is an en-dash and — is an em-dash

Table of contents

You can insert a table of contents using the marker [TOC]:

Comments

Usually, comments in Markdown are just standard HTML comments.
StackEdit extends HTML comments in order to produce useful, highlighted comments in the preview but not in your exported documents.

MathJax

You can render LaTeX mathematical expressions using MathJax, as on math.stackexchange.com:

The Gamma function satisfying Γ(n)=(n1)!nN is via the Euler integral

Γ(z)=0tz1etdt.

Tip: Make sure you include MathJax into your publications to render mathematical expression correctly. Your page/template should include something like:

<script type="text/javascript" src="https://stackedit.io/libs/MathJax/MathJax.js?config=TeX-AMS_HTML"></script>

NOTE: You can find more information:

  • about Markdown syntax here,
  • about Markdown Extra extension here,
  • about LaTeX mathematical expressions here,
  • about Prettify syntax highlighting here,
  • about Highlight.js syntax highlighting here.

var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var flash = require('express-flash');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');
var oauth = require('./routes/oauth');


  1. StackEdit is a full-featured, open-source Markdown editor based on PageDown, the Markdown library used by Stack Overflow and the other Stack Exchange sites.
  2. GitHub Flavored Markdown (GFM) is supported by StackEdit.
  3. Here is the text of the footnote.