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.

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`:

```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 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',{ 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 $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',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.

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',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">
    ☰
  </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.

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

Source codes

Check the sample codes.

Getting Started with AngularJS 1.5 and ES6: part1的更多相关文章

  1. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. ios – 多个项目和Cocoapods

    解决方法我在工作中遇到了类似的问题,我发现更好的是将项目结构改为使用Cocoapods.我认为您的正确解决方案,或至少正确的路径是将您的公共项目变成本地,privatepod.我实现了我的共同项目,并且我的应用程序项目也配置了CocoaPods,使用该私有pod.最后一句话,当通过CocoaPods构建一个共同的库项目时,您将需要覆盖该项目中的“其他链接器标志”构建设置,就像在CocoaPods创建和管理的Pods项目中一样.让我知道这是否适合你!

  3. 在IOS9中的Cordova应用程序使用JQuery / Javascript的window.history问题

    在两个测试用例中唯一改变的是Cordova.js.解决方法我看到这是几个星期前,但我会发布这个,以防其他人遇到它.听起来它可能与iOS9中的哈希更改生成的导航事件有关.如果是这样,可以将其添加到index.html以禁用哈希侦听:

  4. iOS 5上的jQuery事件

    解决方法在Apple开发论坛上由一个人回答:我需要在将元素添加到DOM之后才绑定(),如下所示:

  5. android – Guava:java.lang.NoClassDefFoundError – com.google.common.collect.HashBiMap

    当我使用从这里下载的guava库时,我目前面临java.lang.NoClassDefFoundError:com.google.common.collect.HashBiMap的问题:http://code.google.com/p/guava-libraries/我已经将guava-12.0.jar添加到我的项目中作为参考库但我仍然得到错误.你能就这个问题提出一些建议吗?谢谢您的帮助我得到的错

  6. Android Studio是否支持用于Android UI设计的AngularJS?

    我对AndroidStudio有疑问:AS在设计XML文件时是否支持AngularJS代码,例如:对于小动画或效果?

  7. android – 无法解析API文件“frameworks / base / api / current.txt”

    我尝试在Android框架中添加一些文件.一切顺利,除了在编译结束时,我得到低于错误.我也试过makeupdate-api,但没有运气,每次编译它都会给出以下错误.如果有人知道如何解决这个问题,请告诉我.解决方法这个问题的原因是,原因:–我在Android框架中添加私有类,这些类文档/声明必须添加到“frameworks/base/api/current.txt”解决方案:–根据错误日志,有两种解

  8. android – 如何使用ClientID和ClientSecret在Phonegap中使用Angularjs登录Google OAuth2

    我正尝试使用Angularjs(使用IonicFramework)通过GoogleOAuth2从我的Phonegap应用程序登录.目前我正在使用http://phonegap-tips.com/articles/google-api-oauth-with-phonegaps-inappbrowser.html进行登录.但是当我使用Angular-UI-RouterforIonic时,它正在创建非常

  9. android – Phonegap本地构建 – jquery ajax错误:readystate 0 responsetext status 0 statustext error

    解决方法您是否在索引文件中包含了内容安全元标记?

  10. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

随机推荐

  1. Angular2 innerHtml删除样式

    我正在使用innerHtml并在我的cms中设置html,响应似乎没问题,如果我这样打印:{{poi.content}}它给了我正确的内容:``但是当我使用[innerHtml]=“poi.content”时,它会给我这个html:当我使用[innerHtml]时,有谁知道为什么它会剥离我的样式Angular2清理动态添加的HTML,样式,……

  2. 为Angular根组件/模块指定@Input()参数

    我有3个根组件,由根AppModule引导.你如何为其中一个组件指定@input()参数?也不由AppModalComponent获取:它是未定义的.据我所知,你不能将@input()传递给bootstraped组件.但您可以使用其他方法来做到这一点–将值作为属性传递.index.html:app.component.ts:

  3. angular-ui-bootstrap – 如何为angular ui-bootstrap tabs指令指定href参数

    我正在使用角度ui-bootstrap库,但我不知道如何为每个选项卡指定自定义href.在角度ui-bootstrap文档中,指定了一个可选参数select(),但我不知道如何使用它来自定义每个选项卡的链接另一种重新定义问题的方法是如何使用带有角度ui-bootstrap选项卡的路由我希望现在还不算太晚,但我今天遇到了同样的问题.你可以通过以下方式实现:1)在控制器中定义选项卡href:2)声明一个函数来改变控制器中的散列:3)使用以下标记:我不确定这是否是最好的方法,我很乐意听取别人的意见.

  4. 离子框架 – 标签内部的ng-click不起作用

    >为什么标签标签内的按钮不起作用?>但是标签外的按钮(登陆)工作正常,为什么?>请帮我解决这个问题.我需要在点击时做出回复按钮workingdemo解决方案就是不要为物品使用标签.而只是使用divHTML

  5. Angular 2:将值传递给路由数据解析

    我正在尝试编写一个DataResolver服务,允许Angular2路由器在初始化组件之前预加载数据.解析器需要调用不同的API端点来获取适合于正在加载的路由的数据.我正在构建一个通用解析器,而不是为我的许多组件中的每个组件设置一个解析器.因此,我想在路由定义中传递指向正确端点的自定义输入.例如,考虑以下路线:app.routes.ts在第一个实例中,解析器需要调用/path/to/resourc

  6. angularjs – 解释ngModel管道,解析器,格式化程序,viewChangeListeners和$watchers的顺序

    换句话说:如果在模型更新之前触发了“ng-change”,我可以理解,但是我很难理解在更新模型之后以及在完成填充更改之前触发函数绑定属性.如果您读到这里:祝贺并感谢您的耐心等待!

  7. 角度5模板形式检测形式有效性状态的变化

    为了拥有一个可以监听其包含的表单的有效性状态的变化的组件并执行某些组件的方法,是reactiveforms的方法吗?

  8. Angular 2 CSV文件下载

    我在springboot应用程序中有我的后端,从那里我返回一个.csv文件WheniamhittingtheURLinbrowsercsvfileisgettingdownloaded.现在我试图从我的角度2应用程序中点击此URL,代码是这样的:零件:服务:我正在下载文件,但它像ActuallyitshouldbeBook.csv请指导我缺少的东西.有一种解决方法,但您需要创建一个页面上的元

  9. angularjs – Angular UI-Grid:过滤后如何获取总项数

    提前致谢:)你应该避免使用jQuery并与API进行交互.首先需要在网格创建事件中保存对API的引用.您应该已经知道总行数.您可以使用以下命令获取可见/已过滤行数:要么您可以使用以下命令获取所选行的数量:

  10. angularjs – 迁移gulp进程以包含typescript

    或者我应该使用tsc作为我的主要构建工具,让它解决依赖关系,创建映射文件并制作捆绑包?

返回
顶部