Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

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-outletselectorを入れる。
<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が自動で作成される。(これは、djangopython 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

  • package.jsonを作成する(djangoでいうところの、requirements.txtにあたるところ?)

  • $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より楽かもしんないな。