Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Angular Handson Geek Women Japan

Step.1: 簡易サーバ

Node.js 若しくは Python、 Ruby で簡易サーバが利用出来るように準備します

node:

$ npm install live-server -g
$ live-server

node:

$ npm install http-server -g
$ http-server

Ruby

$ ruby -run -e httpd -- -p 8000 

or

$ ruby -rwebrick -e 'WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 8000).start'

Python 2系

$ python -m SimpleHTTPServer

VSCode スニペット

  1. Install Visual Studio Code 0.10.1 or higher
  2. Launch Code
  3. From the command palette Ctrl-Shift-P (Windows, Linux) or Cmd-Shift-P (OSX)
  4. Select Install Extension
  5. Choose the extension
  6. Reload Visual Studio Code

Angular v2 TypeScript Snippets

Step.2: 開発環境作成

はじめに任意のプロジェクト用フォルダーを作成し、作成したフォルダーへに移動します

$ mkdir angular-handson && cd $_

SPA の起点となる HTML ファイル等を作成します

$ touch index.html
$ touch style.css
$ touch config.js

それぞれファイルの中身は次の通りです

index.html

<!DOCTYPE html>
<html>
  <head>
    <base href="." />
    <title>Angular PlayGround</title>
    <link rel="stylesheet" href="style.css" />
    <script src="https://unpkg.com/zone.js/dist/zone.js"></script>
    <script src="https://unpkg.com/zone.js/dist/long-stack-trace-zone.js"></script>
    <script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>
    <script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>
    <script src="config.js"></script>
    <script>
    System.import('app')
      .catch(console.error.bind(console));
  </script>
  </head>
  <body>
    <my-app>loading...</my-app>
  </body>
</html>

style.css

(empty)

config.js

System.config({
  //use typescript for compilation
  transpiler: 'typescript',
  //typescript compiler options
  typescriptOptions: {
    emitDecoratorMetadata: true
  },
  paths: {
    'npm:': 'https://unpkg.com/'
  },
  //map tells the System loader where to look for things
  map: {
    
    'app': './src',
    
    '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
    '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
    '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
    '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
    '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
    '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
    '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
    '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
    
    '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js',
    '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js',
    '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js',
    '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js',
    '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
    '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js',
    '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js',
    
    'rxjs': 'npm:rxjs',
    'typescript': 'npm:typescript@2.0.2/lib/typescript.js'
  },
  //packages defines our app package
  packages: {
    app: {
      main: './main.ts',
      defaultExtension: 'ts'
    },
    rxjs: {
      defaultExtension: 'js'
    }
  }
});

Angular のコマンドラインツール angular-cli を利用した場合にはこうした設定は不要です。angular-cli はスカッフォールドツールで開発に必要なテンプレートを簡単に生成することが可能だからです。

Angular のコードは src ディレクトリへ格納します

$ mkdir src

準備はここまでですが、まだ動きません。 Angular を実行するためのコードを src ディレクトリの中に記述します。

$ touch src/main.ts
$ touch src/app.ts

それぞれ

main.ts

//main entry point
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app';

platformBrowserDynamic().bootstrapModule(AppModule);

app.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'my-app',
  template: 'feature.component.html'
})
export class App implements OnInit {
  constructor() { }

  ngOnInit() { }
}

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

@NgModule({
  imports: [BrowserModule],
  exports: [],
  declarations: [App],
  providers: [],
  bootstrap: [App]
})
export class AppModule { }

app.ts ではスニペットを利用します。Component では a-com を、 Module では a-mo とタイプしエンターキーを押すとテンプレートが出力されます。若干内容を修正すれば完了です。

Node の http-server や lite-server を起動し実行されることを確認してください。

Step.3: ビルトインディレクティブ

Angular の基本的な機能であるビルトインディレクティブ(Angular が提供しているディレクティブを指しています)について触れていきます。

ngModel

ngModel を利用するための準備として FormsModule を登録します

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

@NgModule({
  imports: [
    BrowserModule,
    FormsModule
  ],
  exports: [],
  declarations: [App],
  providers: [],
  bootstrap: [App]
})
export class AppModule { }

template を次のように書き換えます。ブラウザにテキストボックスが表示され入力すると即座に入力した値が表示されると思います。Angular の特徴であるバインディングを利用しています。

<input type="text" [(ngModel)]="hoge">
<span>{{hoge}}</span>

[value]

[value]を利用しデータバインドしますが、こちらは片方向のバインドです。

<input type="text" [(ngModel)]="hoge">
<input [value]="hoge">

ngIf

もう少しプログラムチックな動きをさせるために ngIf を利用してみます。テキストボックスに入力した値が 1 のときにメッセージを出力するというロジックを記述してみます。

<input type="text" [(ngModel)]="hoge">
<span *ngIf="hoge==='1'">1が入力されました<span>

ng-invalid と ng-dirty

テキストボックスに対して必須チェックを実装することが可能です。先ほどのサンプルはテキストボックスに required を入れることでその項目が必須項目となります。

<input type="text" [(ngModel)]="hoge" required>

画面上、警告も何も表示されないので何が起きているのか確認できませんが、カスケードスタイルシートを定義するとよく理解できます。

input.ng-invalid {
  border-color: #ff0000;
}

何も入力されていないときにはテキストボックスの縁が赤くなっていることが確認できます。ただ、これだと入力前から赤いので UI としてはイマイチといった感じなので、ここで ng-dirty を利用します。カスケードスタイルシートを次のように変更してください。

input.ng-invalid.ng-dirty {
  border-color: #ff0000;
}

こうすることで入力前は警告なしで、入力後、空欄にした場合は赤くなることが確認できます。

$invalid と $dirty を利用する

入力されてなかった場合、赤くなりましたがメッセージも表示します。警告メッセージは「必須入力です」にしましょう。

<form #f="ngForm" novalidate>
  <input type="text" name="hoge" ngModel required>
  <p [hidden]="!f.form.dirty || f.form.valid">必須入力です</p>
</form>

ngFor

コンストラクタでデータを定義し ngFor で定義したデータを表示します。

<form #f="ngForm" novalidate>
  <input type="text" name="hoge" ngModel required>
  <p [hidden]="!f.form.dirty || f.form.valid">必須入力です</p>
</form>
<ul>
  <li *ngFor="let data of demoData">{{data.name}} - {{data.age}}</li>
</ul>

Appクラスにデータを追加してください。

export class App implements OnInit {
  constructor() { }

  ngOnInit() { }

  demoData: any = [
    {name: '山田', age: 24},
    {name: '田中', age: 28},
    {name: '佐藤', age: 18},
    {name: '井上', age: 32},
    {name: '高橋', age: 46}
  ]
}

Step.4: ルーティング

SPA の基本的な機能としてルーティングを扱います。ルーティング時のルートコンポーネントを

  • HomeComponent
  • IssueComponent
  • WikiComponent

とします。スニペットを使ってそれぞれ作成します

@Component({
  selector: 'my-home',
  template: 'home.component.html'
})
export class HomeComponent implements OnInit {
  constructor() { }

  ngOnInit() { }
}

@Component({
  selector: 'my-issue',
  template: 'issue.component.html'
})
export class IssueComponent implements OnInit {
  constructor() { }

  ngOnInit() { }
}

@Component({
  selector: 'my-wiki',
  template: 'wiki.component.html'
})
export class WikiComponent implements OnInit {
  constructor() { }

  ngOnInit() { }
}

次にルーティングの設定をします。スニペット a-rouを使って作成します。

import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const appRoutes: Routes= [
  { path: '', redirectTo: 'home', pathMatch: 'full'},
  { path: 'home', component: HomeComponent },
  { path: 'issue', component: IssueComponent },
  { path: 'wiki', component: WikiComponent }
];

NgModule にルータの設定を行い

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    RouterModule.forRoot(appRoutes)
  ],
  exports: [],
  declarations: [
    App,
    HomeComponent,
    IssueComponent,
    WikiComponent
  ],
  providers: [],
  bootstrap: [App]
})
export class AppModule { }

App のテンプレートにページ切り替え用の記述をすると完了です

<h1>Issue Tracker</h1>
<ul>
  <li><a routerLink="home">Home</a></li>
  <li><a routerLink="issue">Issue</a></li>
  <li><a routerLink="wiki">Wiki</a></li>
</ul>
<router-outlet></router-outlet>

参考

Start Angular

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment