Angular4入門_Vol.4
参考サイト
https://www.codingforentrepreneurs.com/projects/try-angular-v4/
Dynamic Routing of Components
- video-detail.component.tsにコードを追記する。
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'video-detail', templateUrl: './video-detail.component.html', styleUrls: ['./video-detail.component.css'] }) export class VideoDetailComponent implements OnInit { constructor(private route: ActivatedRoute) { } // instanceが作成されたときに自動でrouteのアノテーションを実行するぽい。 ngOnInit() { this.route.params.subscribe(params => { console.log(params) //subscribeは、変更があったときに、その変更を受取るメソッドのこと?なんであんまり解説がないんだろう。。。 }) // 上記のarrow関数は、以下と同じ意味 // this.route.params.subscribe(function(params){ // console.log(params) //}) } }
- video-list.component.html の、href部分を修正する。
<p> {{ title }} </p> <p *ngFor='let item of videoList'> <a href="videos/{{ item.slug }}" *ngIf='item.slug == "item-1"'>{{ item.name }}</a> <a href="videos/{{ item.slug }}" *ngIf='item.slug != "item-1"' style='color:red;'>{{ item.name }}</a> </p>
無事routingが機能した!console.logにparams objectも表示された。
video-detail.component.tsにさらにコードを追記する。subscribeの解放と、slug変数の設定をする。
import { Component, OnInit, OnDestroy } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'video-detail', templateUrl: './video-detail.component.html', styleUrls: ['./video-detail.component.css'] }) export class VideoDetailComponent implements OnInit, OnDestroy { private routeSub:any; //routeSub 変数をany で作成する slug: string; // slugをstringとして定義する。 constructor(private route: ActivatedRoute) { } ngOnInit() { // データバインドされた入力値を初期化後に実行される。 this.routeSub = this.route.params.subscribe(params => { console.log(params) this.slug = params['slug'] //this.slugに、paramsオブジェクトのslug のvalueを代入する。 }) } ngOnDestroy(){ //ngOnDestroyは、ディレクティブ・コンポーネントを破棄する前に呼ばれる。 this.routeSub.unsubscribe() //routeSubのsubscribeを解除する。unsubscribe } }
- video-detail.component.htmlに追記する。
<p> {{ slug }} video-detail works! </p>
まとめ
subscribeがふわっとしてる。subscribeは3つの引数を取り、subscribe(success, error, complete)とのことらしいので、ここでは、successのときの処理を書いたという感じか。subscribeは、特定のurlにアクセスして、その時の結果に応じて処理を変更できるということにしておくか。
unsubscribeは、subscribeを解除するために設定するらしい。メモリーを開放するとかそういう意味があるぽい。
ngOnInit, ngOnDestroyなどのライフサイクルはなんとなくしか理解してないので、ここを理解するのは重要かもしれんな。。。
privateと、publicの違いもよくわからんけど、たぶん、外に表示しないものは、privateで、それ以外はpublicというざっくりした認識でいいのかな。
Angular4入門_Vol.3
参考サイト
https://www.codingforentrepreneurs.com/projects/try-angular-v4/
Mapping Urls with Router Moudle
routermoduleを使って、urls のmappingをする。
まず、src/app/app.routing.tsファイルを作成する。
import { NgModule } from '@angular/core'; import { RouterModule, Routes} from '@angular/router'; import { VideoListComponent } from './video-list/video-list.component'; import { VideoDetailComponent } from './video-detail/video-detail.component'; const appRoutes: Routes = [ //appRoutes は、Routesでアノテーションする。Routesは、すでにimportしたclass { path:"videos", // pathは、url component: VideoListComponent, // pathにアクセスしたときに実行されるcomponentのことかな。outlet-routerの対象になるselectorってことなのかな。 }, { path:"videos/:slug", //:slugの部分は、djangoでいうと{pk:pk}とかに当たる部分かな。 component: VideoDetailComponent, }, ] // 以下はいまのところさっぱりわからんから、公文としておぼえておこう。 @NgModule({ imports: [ RouterModule.forRoot( appRoutes ) ], exports:[ RouterModule ] }) export class AppRoutingModule{ }
- 次に作成した、AppRoutingModuleをapp.module.tsにimportする。
... import { AppRoutingModule } from './app.routing'; ... @NgModule({ declarations: [ AppComponent, VideoListComponent, VideoDetailComponent ], imports: [ BrowserModule, FormsModule, HttpModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
- app.component.htmlに
router-outlet
selectorを入れる。
<h1>{{ title }} is cool!</h1> <p>{{ description }}</p> <hr> <video-list></video-list> <router-outlet></router-outlet>
- localhost:4200にアクセスしてみる。。。error発生!
Error: Cannot match any routes. URL Segment: 'item-3' Error: Cannot match any routes. URL Segment: 'item-3'
app.routing.tsに設定した通り、
http://127.0.0.1:4200/videos
にアクセスしてみる。videos-listはうまく表示された!http://127.0.0.1:4200/videos/item-1
にアクセスしてみる。こちらも、video-detail works!が表示された!app.routing.ts を少し修正する。pathが無いときのcomponentも指定しておく。これで、
http://127.0.0.1:4200
のときに、VideoListComponentが実行されるようになる。
... const appRoutes: Routes = [ { path:"", component: VideoListComponent, }, { path:"videos", component: VideoListComponent, }, { path:"videos/:slug", component: VideoDetailComponent, }, ] ...
Angular4入門_Vol.2
参考サイト
https://www.codingforentrepreneurs.com/projects/try-angular-v4/
6 - ngFor & ngIf
- ngForのテストをするために、video-list.component.tsを修正する。
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'video-list', templateUrl: './video-list.component.html', styleUrls: ['./video-list.component.css'] }) export class VideoListComponent implements OnInit { title = "tenshinoenogu!"; videoList = ["Item 1", "Item 2", "Item 3"]; //listを追加 constructor() { } ngOnInit() { } }
- 該当のtemplateUrlのhtmlを修正する。
<p> {{ title }} </p> <p *ngFor='let item of videoList'> {{ item }} </p>
これで、videoListに格納されているvalueが表示される。
さらにvideoListに、オブジェクトリストを格納してみる。
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'video-list', templateUrl: './video-list.component.html', styleUrls: ['./video-list.component.css'] }) export class VideoListComponent implements OnInit { title = "Video List!"; // videoList = ["Item 1", "Item 2", "Item 3"]; Json object videoList = [ { name: "Item 1", link: "item-1" }, { name: "Item 2", link: "item-2" }, { name: "Item 3", link: "item-3" }, ] constructor() { } ngOnInit() { } }
- object listからvalueを取り出すためにhtmlを修正する。
<p> {{ title }} </p> <p *ngFor='let item of videoList'> <a href="{{ item.link }}">{{ item.name }}</a> </p>
- django風にわかりやすくするために、videoListのobjectのlinkをslugにする。
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'video-list', templateUrl: './video-list.component.html', styleUrls: ['./video-list.component.css'] }) export class VideoListComponent implements OnInit { title = "Video List!"; // videoList = ["Item 1", "Item 2", "Item 3"]; videoList = [ { name: "Item 1", slug: "item-1" }, { name: "Item 2", slug: "item-2" }, { name: "Item 3", slug: "item-3" }, ] constructor() { } ngOnInit() { } }
*ngIf
を使ってみる。
<p> {{ title }} </p> <p *ngFor='let item of videoList'> <a href="{{ item.slug }}" *ngIf='item.slug == "item-1"'>{{ item.name }}</a> <a href="{{ item.slug }}" *ngIf='item.slug != "item-1"' style='color:red;'>{{ item.name }}</a> </p>
django風に書くと
{% for item in videoList %}
ってところだね。重要なのは、ngFor, ngIfは、
などtagの塊ごとに、評価されるところかな。
{}で囲まれたものをjavascript object、単にvalueのlistの場合を、JSONobjectとよんでいた。これはできるだけ、そのような認識で統一するようにしよう。
まとめ
- ngForなどはtagの塊ごとに適用される。
- 文法などはdjangoのtemplate engineに少し似てる。
Angular4入門_No.1
参考サイト
https://www.codingforentrepreneurs.com/projects/try-angular-v4/
Getting Started with Angular v4
$ng new srvup
コマンドを実行すると、新しいangularのproject、srvupが作成される。angularに必要なnode.jsのpackageをinstallするので、ちょっと時間がかかる。(django-admin startprojectと似たようなもの)
App Module & Component
angular project内(ここでは、srvupディレクトリ)にcdして、
ng serve
を実行してみる。app works!
が表示されればOK。app.component.ts
を修正しながら、angularの機能を試してみる。
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', // template: `<p>{{ title }} is cool! {{ description }}</p>`, //templateには、直接htmlの記述もできる styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'Hello srvup!!2 '; description = '新しいアプリケーションです'; } // django 風に書くと以下のようなこと // def some_view(request): // return render(request, "template.html",{})
- selector名を修正する。
import { Component } from '@angular/core'; @Component({ selector: 'srvup-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'Hello srvup!!2 '; description = '新しいアプリケーションです'; }
- index.htmlを修正する。
<body> <srvup-root>Loading...</srvup-root> </body>
4 - Ng Generate new Component
componentもng cli で作成できる。
$ ng g component videoList
を実行すると、videoListという名前のcomponentが作成される。続いて、
$ ng g component video-detail
を実行する。video-list.component.tsは以下のようになっている。
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'video-list', //app-の部分は削除する templateUrl: './video-list.component.html', styleUrls: ['./video-list.component.css'] }) export class VideoListComponent implements OnInit { constructor() { } ngOnInit() { } }
- app.module.ts の、bootstrapをVideoListComponentに変更してみる。
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpModule } from '@angular/http'; import { AppComponent } from './app.component'; import { VideoListComponent } from './video-list/video-list.component'; import { VideoDetailComponent } from './video-detail/video-detail.component'; @NgModule({ declarations: [ AppComponent, VideoListComponent, VideoDetailComponent ], imports: [ BrowserModule, FormsModule, HttpModule ], providers: [], bootstrap: [VideoListComponent] //ここを修正する。 }) export class AppModule { }
- ただこのままでは、
The selector "video-list" did not match any elements
とerrorがでて表示されない。そのため、index.htmlのselectorタグを修正する。
<body> <video-list>Loading...</video-list> </body>
- 以上で、componentとselectorタグの使い方のレクは終了。それぞれ、selector名をもともとのapp-root, bootstrap[AppComponent]に戻しておく。
5 - Selectors & Components
- selectorを使ってみる。app.component.htmlに追記してみる。
<h1>{{ title }} is cool!</h1> <p>{{ description }}</p> <video-list></video-list> <video-detail></video-detail>
- video-list.component.tsにtitle変数を追記してみる。
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'video-list', templateUrl: './video-list.component.html', styleUrls: ['./video-list.component.css'] }) export class VideoListComponent implements OnInit { title = "tenshinoenogu!"; constructor() { } ngOnInit() { } }
- htmlもcontextを使うように修正してみる。
<p> {{ title }} </p>
- うまくいった!
まとめ
- componentは、djangoのstartappに似てる。app.module.tsは、settingsの機能の一部に近いな。
- selectorタグは便利そう。
Angular4入門 ~setup編~
参考サイト
https://www.codingforentrepreneurs.com/projects/setup-angular/how-setup-angular/?play=true https://www.codingforentrepreneurs.com/blog/angular-setup-guide/
How to Setup Angular
- Install Angluar CLI via npm:
npm install -g @angular/cli
- Navigate to project directory:
$ mkdir appDir && cd appDir $ ng new cfe-app
- ng new で、angularアプリ作成なmoduleなどが一通りinstallされる。以下が表示されたら成功。(django-admin projectのようなものかな。)
Installing packages for tooling via npm. Installed packages for tooling via npm. Project 'cfe-app' successfully created.
- local serverを起動する。
$ cd ~/path/cfe-app/ $ ng serve
app works!
と表示されれば成功!ng serve
が実行されている状態で、app.component.tsを修正する。
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'Hi there again!'; }
ng build
を実行すると、distディレクトリが自動作成される。この中身が実際にレンダリングされて、出力されるコードになるのかな。ng g component videoList
を実行すると、videoListのcomponentが自動で作成される。(これは、djangoのpython manage.py startapp みたいなもんやな。)さらにすごいのは、
app.module.ts
に自動で、videoList
moduleが追記されているところ。app.component.html
に<app-video-list></app-video-list>
を追記する。video-list-worksの表示されたら、成功!!(^^)
まとめ
- コマンドラインツールは超便利!これはどんどん使わないと。
Angularのための、TypeScript入門 その5
参考サイト
https://www.codingforentrepreneurs.com/projects/getting-started-typescript/ https://www.codingforentrepreneurs.com/blog/typescript-setup-guide/
Package.json - npm init
$npm init
をターミナルに打ち込む。あとは手順通りに項目を入力していくと、package.jsonが自動で作成される。$npm test
など任意のコマンドを登録できる。以下のように登録すると、$npm run main
とターミナルにコマンドをうつと、webpack --watch --optimize-minimize
が実行される。
"scripts": { "main": "webpack --watch --optimize-minimize", "server": "http-server -c-1", "test": "" },
jQuery, Typings, and npm
$ npm install typings
をinstallする。ただこの時点では、package.jsonには、typingsのinstallが反映されていない。
$ typings install dt~jquery --global --save
を実行する。(globalだとうまくいかない場合は、localで処理する)$ typings install
を実行する。(うまくいかない場合は、localにtypingsをinstallするとかかな)tsconfig.json
にtypings以降のフォルダも参照にするように記載する。
{ "compilerOptions": { "module": "commonjs", "outDir": "dist/", "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true }, "include": [ "src/*", "typings/*" ], "exclude": [ "node_modules", "**/*.spec.ts" ] }
main.ts
にimportして、jqueryのコードを書いてみる。
import * as $ from "jquery"; import { MustHaveCoffee } from './coffee/getcoffee'; class ReallyCoffee extends MustHaveCoffee { coffeeType = 'tenshi'; constructor(){super()} f(input: boolean){ let a = 100 if (input) { let b = a + 100012 return b; } return a; } setCoffeeType(name:string){ console.log("hello there " + "test " + this.coffeeType) $("body").css('background-color', 'red') // ここがjquery $("body").html("<h1>" + this.coffeeType + "</h1>") } } let newCoffee = new ReallyCoffee(); newCoffee.f(true); newCoffee.setCoffeeType("bulletproof"); let odlCoffee = new MustHaveCoffee()
$npm run server
すると、以下のerrorが出てしまう。
ERROR in ./src/main.ts Module not found: Error: Can't resolve 'jquery' in '/path/tsSetup/src' @ ./src/main.ts 13:8-25
$npm link jquery
で、localと、globalのjqueryをlinkさせる?とうまくいった!$npm install jquery --save
というように、saveをつけて実行するとpackageにinstallされる。
Angularのための、TypeScript入門 その4
参考サイト
https://www.codingforentrepreneurs.com/projects/getting-started-typescript/
Typescript - Classes - Part 3
main.tsをsrc/内に移動させる。
archiveというフォルダを作成して、不要になったmain.tsなどを移動させておく。(なぜ削除しないかはいまのところ不明)
webpack.config.js
に、新しいmain.tsのpathを設定する。
var path = require('path'); module.exports = { entry: './src/main.ts', resolve: { extensions: ['.webpack.js', '.web.js', '.ts', '.js'] }, module: { loaders: [ { test: /\.ts$/, loader: 'ts-loader' } ] }, output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } }
- webpack –watch でerrorが発生!
ERROR in /path/tsconfig.json error TS18003: No inputs were found in config file 'tsconfig.json'. Specified 'include' paths were '["*"]' and 'exclude' paths were '["node_modules","**/*.spec.ts"]'. ERROR in ./src/main.ts Module build failed: error while parsing tsconfig.json
- tsconfig.jsonを修正する。inclludeに、
"src/*",
を追記する。これで、error解消!
{ "compilerOptions": { "module": "commonjs", "outDir": "dist/", "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true }, "include": [ "src/*", "*" ], "exclude": [ "node_modules", "**/*.spec.ts" ] }
- main.tsに、MustHaveCoffeeを継承して独自のメソッドを追記する。
import { MustHaveCoffee } from './coffee/getcoffee'; class ReallyCoffee extends MustHaveCoffee { constructor(){super()} // ここで、constructor の継承を行う f(input: boolean){ // ここはfunctionという名前で指定しなくてもいいのか?それは省略できるのか。 let a = 100 if (input) { let b = a + 100012 return b; } return a; } } let newCoffee = new ReallyCoffee() let count = newCoffee.f(true) console.log(count) let odlCoffee = new MustHaveCoffee()
- MustHaveCoffee classにsetCoffeeTypeを追記する。
export class MustHaveCoffee{ coffeeType: string; constructor(){ console.log("Make it bulletproof") } setCoffeeType(name:string){ this.coffeeType = name } }
- ReallyCoffee classで上書きなどのテストをしてみる。
import { MustHaveCoffee } from './coffee/getcoffee'; class ReallyCoffee extends MustHaveCoffee { coffeeType = 'tenshi'; constructor(){super()} // ここで、classの継承を行う f(input: boolean){ let a = 100 if (input) { let b = a + 100012 return b; } return a; } setCoffeeType(name:string){ // super.setCoffeeType(name) このように記述するとオーバーロードできる。 // super(ReallyCoffee, self).setCoffeeType(name) >python風 console.log("hello there " + "test " + this.coffeeType) } } let newCoffee = new ReallyCoffee(); newCoffee.f(true); newCoffee.setCoffeeType("bulletproof"); let odlCoffee = new MustHaveCoffee()
まとめ
- 実は継承の部分は、記述がpythonより楽かもしんないな。