文档章节

Getting Started with AngularJS 1.5 and ES6: part1

hantsy
 hantsy
发布于 2016/10/05 09:03
字数 1992
阅读 99
收藏 0

Getting started

Gulp 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 project

Clone 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.

NG6 Starter

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 gulp serve to run this application immediately. Anytime you can navigate to http://localhost:3000 to play the running application.

By default, NG6-stater also provides a simple Gulp task(gulp component) to generate components quickly.

Execute gulp component in the root folder to generate some components for further development use.

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.

  • posts.js is the entry js file of posts component.
  • posts.component.js is the component definition file.
  • posts.controller.js is the controller class for posts component.
  • posts.styl is the component specific style file, it uses Stylus.
  • posts.html is the template file of posts component.
  • posts.spec.js is the testing spec file for posts component.

Reorganize the source codes

Follow 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.constant(), app.run(), app.config() from app.js into standalone files.

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 resources

By default, the NG6-starter repository includes angular(from official AngularJS) and angular-ui-router(from Angular UI team).

Install other Angular NPM packages into this project.

npm install --save angular-messages angular-touch angular-animate

Install angular-toastr which is toastr integration for Angular. We will use it raise notification messsages to client when we perform some actions.

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: css-loader, file-loader and url-loader.

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:

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 index.js file.

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', createdAt: '9/22/16 4:15 PM' },
       { id: 3, title: 'Getting started with Angular2', content: 'Content of Getting started with Angular2', createdAt: '9/22/16 4:15 PM' },
    ]
  }

  $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 $onInit, $onChange, $onDestroy, $postLink etc.

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 $ctrl by default. You can change it by specifying a controllerAs property of component.

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.

Route

In this project, we use angular-ui-router instead of the Angular official router. It is more powerful and provides more features.

For example:

  1. It contains a state machine to manage routings.
  2. It supports nested multi-views.

app component is the root component of this application.

In the app template file: app.html, insert a ui-view directive.

<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', {
      abstract: true,
      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 ui-view diretive defined in app template.

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.

Posts list

Repeat gulp component command and add more components, such as new-post, edit-post, post-detail, and move the generated files in compoents/posts folder. Do not care about the content of them, we will implement them later.

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', [commonSevices, 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> 

ui-sref directive accepts a state name and state params.

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">
    &#9776;
  </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>

ui-sref-active will add class active to the element when route is activated.

navbar

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.

navbar

With help of ui-router-visualizer, you can explore the state tree in a visual graph.

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.

navbar

Source codes

Check the sample codes.

© 著作权归作者所有

hantsy
粉丝 113
博文 88
码字总数 78079
作品 0
浦东
程序员
私信 提问
加载中

评论(0)

linux 环境下 angular2 生成component 报错 ELOOP:too many symbolic links encountered, stat

adaptercat@debian :/project/angular/AngularTest/src/app$ ng generate component t Error: ELOOP: too many symbolic links encountered, stat '/project/angular/AngularTest/node_modul......

adaptercat
2017/10/10
572
1
ngular2 VS Angular4 深度对比:特性、性能

在Web应用开发领域,Angular被认为是最好的开源JavaScript框架之一。 Google的Angular团队已于3月23日发布了Angular4,而期待已久的Angular2版本则是之前版本的完全重构。 对于成熟的开发人员...

机器的心脏
2018/06/02
0
0
AngularJS2.0 教程系列(一)

Why Angular2 Angular1.x显然非常成功,那么,为什么要剧烈地转向Angular2? 性能的限制 AngularJS当初是提供给设计人员用来快速构建HTML表单的一个内部工具。随着时间的推移,各种特性 被加...

笔阁
2015/07/22
2.5W
1
All About Angular 2.0

angular All About Angular 2.0Posted by Rob Eisenberg on November 6th, 2014. Have questions about the strategy for Angular 2.0? This is the place. In the following article I'll e......

Ethan_prog
2015/03/06
151
0
Angular 2 系列: 简介

[Angular 2 Series: Introduction][1] By Max on April 2, 2015 現在, [Angular 2][2] 和 [Ionic 2][3] 呼之欲出。我們超讚的小隊正在為下一個大版本的 Ionic 和 Angular 2 在努力工作。我為...

开源中国匿名会员
2015/05/02
647
0

没有更多内容

加载失败,请刷新页面

加载更多

网站被挂马该怎么彻底的解决 2020年技术篇分享

在网站运营以及优化这方面总是会有一些无所事事的人,冒着风险做各种各样的违规行为的工作,有的时候忽然发现自己的公司网站,就被他人直接挂了木马,那些超链接鼠标点击进来,全部都是灰色内...

网站安全
42分钟前
46
0
php环境搭建+Hello World

1 概述 基础教程,搭建php入门基本环境.环境win10. 2 安装php 2.1 下载 官网点击这里 2.2 安装 其实只需要添加环境变量即可.win+Pause,高级系统设置: Path这里新建一个,刚才的php目录. 2.3 测...

氷泠
45分钟前
40
0
Minecraft Fabric 教程 #9 添加盔甲

首发于Enaium的个人博客 创建一个盔甲类 public class EndArmorMaterials implements ArmorMaterial { [...]} 复制一下内容 private static final int[] BASE_DURABILITY = {13, ......

Enaium
48分钟前
72
0
PHPUnit简介及使用

一、PHPUnit是什么? 1、它是一款轻量级的PHP测试框架,地址:http://www.phpunit.cn 2、手册:http://www.phpunit.cn/ 二、为什么要用PHPUnit? 1、可以通过命令操控测试脚本 2、可以测试性...

dragon_tech
54分钟前
76
0
在微服务架构中监听以太坊合约事件【Eventeum】

当构建大规模DApp时,监视以太坊的事件会变得很痛苦。在这篇文章中,我们将介绍如何使用Eventeum将后端微服务与以太坊智能合约事件之间桥接起来。 以太坊教程链接:Dapp入门 | 电商Dapp实战 ...

区块链教程
今天
80
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部