Getting Started with AngularJS 1.5 and ES6: part1
Getting startedGulp Angular generator is simple and stupid,but it does not embrace Angular 1.5 completely now. And I would like use Webpack in the new Angular 1.x project. AngularClass provides a very simple mininal NG6-starter project with Webpack support. Create projectClone a copy directly into your local disk. git clone https://github.com/AngularClass/NG6-starter <your project name> Enter the project root folder,let's have a glance at the proejct structure. The client holds all source codes of this project. Under client,there is index.html file which is the entry of this application,and also inlcudes two folders: common and components. The common folder is the common place to store services,components,driectives etc which can be shared for the whole application scope. And components folder is the place to save all page oriented components files. Firstly you have to install all dependencies. Execute the following command in the project root folder. npm install Try to run By default,NG6-stater also provides a simple Gulp task( Execute gulp component posts gulp component signin gulp component signup It will generate three folders(posts,signin,signup) in the components folder under client/app. Each component specific folder includes serveral files. As an example,let's have a look at posts folder.
Reorganize the source codesFollow this Angular style guide,which describes ES6 and Angular 1.5 component especially. ES6 module is easy to origanise the source codes. It could autoload index.js in folders and no need to specify index in the path. eg. import CommonModule from './common/'; It will search the index.js file in common folder and load it. I would like change the file name of all entry files to index.js. Finally the project file structure should look like(only show index.js files). |--common --index.js |--components --index.js |--navbar --index.js |--components --index.js |--posts --index.js In every index.js file,it defines an Angular modlule. For example,the index.js in common/components/navbar defines an Angular Module named navbar(to avoid naming conflict,I changed module name to app.common.components.navbar). import angular from 'angular'; import uiRouter from 'angular-ui-router'; import navbarComponent from './navbar.component'; let navbarModule = angular.module('app.common.components.navbar',[ uiRouter ]) .component('navbar',navbarComponent) .name; export default navbarModule; And in the common/components/index.js file,navbar is imported,and it defines a new Angular Module which depends on this navbar module. import angular from 'angular'; import Navbar from './navbar/'; //... let commonComponentsModule = angular.module('app.common.components',[ Navbar,... ]) .name; export default commonComponentsModule; And in the common/index.js file,commonComponentsModule is imported,a new Angular Module is defined. import angular from 'angular'; import commonComponentsModule from './components/'; //... let commonModule = angular.module('app.common',[ commonComponentsModule,//... ]) .name; export default commonModule; Thus the Angular module definition becomes clear,and from top to down,it looks like a tree structure. App |--Common |--Components |--Navbar By the way,I also want to do some clean work on the app.js. Extract the content of app.constants.js: const AppConstants = { appName: "Angular ES6 Sample",jwtKey: "id-token",api: 'http://localhost:8080/blog-api-cdi/api' }; export default AppConstants; app.run.js: import * as vis from 'ui-router-visualizer'; function AppRun(Auth,$rootScope,$state,$trace,$uiRouter,$transitions) { "ngInject"; //... }; export default AppRun; app.config.js: function AppConfig($logProvider,toastrConfig,$httpProvider,$stateProvider,$locationProvider,$urlRouterProvider) { 'ngInject'; // Enable log $logProvider.debugEnabled(true); /* If you don't want hashbang routing,uncomment this line. Our tutorial will be using hashbang routing though :) */ // $locationProvider.html5Mode(true); $locationProvider.html5Mode(true).hashPrefix('!'); $stateProvider .state('app',{ abstract: true,component: 'app' }); $urlRouterProvider.otherwise('/'); } export default AppConfig; Finally imports these files in app.js,it looks like: import 'jquery'; import 'tether'; import 'bootstrap'; import 'bootstrap/dist/css/bootstrap.min.css'; import 'font-awesome/css/font-awesome.min.css'; import angular from 'angular'; import toastr from 'angular-toastr'; import 'angular-toastr/dist/angular-toastr.css'; import 'angular-messages'; import 'angular-animate'; import 'angular-touch'; import uiRouter from 'angular-ui-router'; import Common from './common/'; import Components from './components/'; import AppComponent from './app.component'; import AppRun from './app.run'; import AppConstants from './app.constants'; import AppConfig from './app.config'; const requires = [ 'ngTouch','ngMessages','ngAnimate',toastr,uiRouter,Common,Components ]; angular.module('app',requires) .component('app',AppComponent) .constant('AppConstants',AppConstants) .config(AppConfig) .run(AppRun); As you see,it looks more clear now. You could have noticed I have added some extra resources into this project,such as Bootstrap,FontAwesome etc. Add extra resourcesBy default,the NG6-starter repository includes Install other Angular NPM packages into this project. npm install --save angular-messages angular-touch angular-animate Install npm install --save angular-toastr Install Bootstrap and FontAwesome. npm install --save font-awesome bootstrap@4.0.0-alpha4 jquery tether We use the latest Bootstrap 4.0 here,currently it is still in active development. So maybe some breaking changes will be included in future. If you encounter Bootstrap errors like "Bootstrap requires JQuery" etc. when run this project,even you have import them in the app.js file,try to add the following configuration into webpack.config.file to overcome this issue. plugins:[ new ProvidePlugin({ jQuery: 'jquery',$: 'jquery',jquery: 'jquery',"Tether": 'tether',"window.Tether": 'tether' }),... Another issue you could see is the css font file loading errors. Install webpack plugins: npm install --save-dev css-loader file-loader url-loader Declare these loaders in webpack.config.file. module: { loaders: [ ... { test: /.css$/,loader: 'style!css' },{ test: /.(png|woff|woff2|eot|ttf|svg)(?v=[0-9].[0-9].[0-9])?$/,loader: 'url-loader?limit=100000' } ``` Till now,we have added essential resources into this project. ## Component We have created several components in before steps. In Angular 1.5,a component can be defined as an object and register it via `angular.component()`. Check the content of *posts.component.js* file. It define an object named `postsComponent`: ```javascript import template from './posts.html'; import controller from './posts.controller'; import './posts.styl'; let postsComponent = { restrict: 'E',bindings: {},template,controller }; export default postsComponent; It is registered in let postsModule = angular.module('posts',[commonSevices,uiRouter]) .component('posts',postsComponent) .name; Different from the previous version,in Angular 1.5,controllers and templates are part of components. The controller is still responsive for handling events and serving data bindings for template. class PostsController { constructor() { 'ngInject'; this.name = 'posts'; this.q = ""; this.posts = []; } $onInit() { console.log("initializing Posts..."); this.posts = [ { id: 1,title: 'Getting started with REST',content: 'Content of Getting started with REST',createdAt: '9/22/16 4:15 PM' },{ id: 2,title: 'Getting started with AngularJS 1.x',content: 'Content of Getting started with AngularJS 1.x',{ id: 3,title: 'Getting started with Angular2',content: 'Content of Getting started with Angular2',] } $onDestroy() { console.log("destroying Posts..."); } search() { console.log("query posts by keyword" + this.q); } } export default PostsController; In concept,Angular 1.5 component is very close to Angular 2,which make upgrading to Angular 2 looks more smooth. An component has several lifecycle hooks,such as Let's have a look at posts template file: posts.html. <div class="card"> <div class="card-block bg-faded"> <div class="row"> <div class="col-md-9"> <form class="form-inline" ng-submit="$ctrl.search()"> <div class="form-group"> <input type="text" name="q" class="form-control" ng-model="$ctrl.q" /> </div> <button type="submit" class="btn btn-outline-info">{{'search'}}</button> </form> </div> <div class="col-md-3"> <span class="pull-md-right"> <a href="#" class="btn btn-success" ui-sref="app.new-post">new-post</a> </span> </div> </div> </div> </div> <div class="row"> <div class="col-md-6" ng-repeat="post in $ctrl.posts "> <div class="card card-block"> <h4 class="card-title">{{post.title}}</h4> <h6 class="card-subtitle text-muted">{{post.createdAt}}</h6> <p class="card-text">{{post.content}}</p> <div class="text-md-right"> <a href="# " ui-sref="app.edit-post({id: post.id})">edit</a> <a href="# " ui-sref="app.view-post({id: post.id})">view</a> </div> </div> </div> </div> In posts template file,the controller is alias as let postsComponent = { //... controllerAs:'myCtrl' }; In order to run project and preview the result of posts compoent in browser. You have to configure routing of posts component. RouteIn this project,we use For example:
app component is the root component of this application. In the app template file: <navbar></navbar> <div class="page"> <div class="container"> <div ui-view></div> </div> </div> And we defines state of app in app.config.js. $stateProvider .state('app',component: 'app' }); $urlRouterProvider.otherwise('/'); And defines posts state in components/posts/index.js. import angular from 'angular'; import uiRouter from 'angular-ui-router'; import postsComponent from './posts.component'; let postsModule = angular.module('posts',[uiRouter]) .config(($stateProvider) => { "ngInject"; $stateProvider .state('app.posts',{ url: '/posts',component: 'posts' }); }) .component('posts',postsComponent) .name; export default postsModule; app component route is declared as abstract,there is an abstract property set to true. posts route name is start with app.,which means will be inherited from app. And the posts template view will be rendered as content of the Now try to run this project in browser. Entry root folder,execute the following command. gulp serve Try to navigate to http://localhost:3000. You will see the screen like the following. Repeat Add route config in compoents/posts/index.js file. //... import postDetailComponent from './post-detail.component'; import newPostComponent from './new-post.component'; import editPostComponent from './edit-post.component'; let postsModule = angular.module('posts',uiRouter]) .config(($stateProvider) => { "ngInject"; $stateProvider //... .state('app.view-post',{ url: '/post-detail/:id',component: 'postDetail' }) .state('app.edit-post',{ url: '/edit-post/:id',component: 'editPost' }) .state('app.new-post',{ url: '/new-post',component: 'newPost' }); }) //... .component('postDetail',postDetailComponent) .component('newPost',newPostComponent) .component('editPost',editPostComponent) .name; export default postsModule; We have added route link in posts.html. For example: <a href="#" class="btn btn-success" ui-sref="app.new-post">new-post</a> <a href="# " ui-sref="app.edit-post({id: post.id})">edit</a> <a href="# " ui-sref="app.view-post({id: post.id})">view</a>
If the application is running,it should be sync with browser by default. Try to navigate to new-post,edit-post,post-detail pages by click these links. Try to add posts and new-post link into the navbar component. Modify the common/compoents/navbar/navbar.html. <nav class="navbar navbar-fixed-top navbar-light bg-faded" style="background-color: #e3f2fd;"> <div class="container"> <a class="navbar-brand" ui-sref="app.home" href="#"><i class="fa fa-home"></i>ANGULAR ES6</a> <button class="navbar-toggler hidden-sm-up" type="button" data-toggle="collapse" data-target="#exCollapsingNavbar" aria-controls="exCollapsingNavbar2" aria-expanded="false" aria-label="Toggle navigation"> ? </button> <!-- Collect the nav links,forms,and other content for toggling --> <div class="collapse navbar-toggleable-xs" id="exCollapsingNavbar"> <ul class="nav navbar-nav"> <li class="nav-item" ui-sref-active="active"><a class="nav-link" href="#" ui-sref="app.posts">{{'posts'}}</a></li> <li class="nav-item" ui-sref-active="active"><a class="nav-link" href="#" ui-sref="app.new-post">{{'new-post'}}</a></li> <li class="nav-item" ui-sref-active="active"><a class="nav-link" href="#" ui-sref="app.about">{{'about'}}</a></li> </ul> <!-- /.navbar-collapse --> </div> </div> <!-- /.container-fluid --> </nav>
Angular UI Router provides some tools to track the route change. Add the following codes into app.run.js to activate transition track. $trace.enable('TRANSITION'); You will the state transition info in browser console when state is changing. With help of npm install --save ui-router-visualizer Add the following codes to app.run.js. import * as vis from 'ui-router-visualizer'; //... vis.visualizer($uiRouter); The visual graph will be displayed at the bottom of the page. Source codesCheck the sample codes. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |