tag:crieit.net,2005:https://crieit.net/tags/Angular2/feed 「Angular2」の記事 - Crieit Crieitでタグ「Angular2」に投稿された最近の記事 2018-09-12T17:47:10+09:00 https://crieit.net/tags/Angular2/feed tag:crieit.net,2005:PublicArticle/14261 2017-03-10T08:49:58+09:00 2018-09-12T17:47:10+09:00 https://crieit.net/posts/CakePHP3 一人もくもく会をCakePHP3のみに変更 <p>Angular + CakePHP3 で作成していた</p> <p><a target="_blank" rel="nofollow noopener" href="https://mokumoku.alphabrend.com/">一人もくもく会</a></p> <p>だが、Angularを捨ててCakePHPのみに修正した。</p> <p>お客さんのために作成したサイトでも何でもないのでSEO対策とかどうでも良かったのでAngularを入れて試したのだが、<br /> そもそもGoogleボットがレンダリングした状態を認識すらしてくれなかった。</p> <p>インデックスもされないし、コンテンツも取得されない。<br /> 流石にそれはサイトとして存在させるメリットすらないのでAngularを使うのをやめた。</p> <h3 id="Fetch as Google"><a href="#Fetch+as+Google">Fetch as Google</a></h3> <p>Search ConsoleにFetch as Googleという機能があり、<br /> クローラに実際にどのようにサイトが見えているかを確認できるのだが、<br /> それを実行したところ「Loading...」のみが表示されていた。</p> <h3 id="原因"><a href="#%E5%8E%9F%E5%9B%A0">原因</a></h3> <p>原因は不明。<br /> ただ、公開直後はFetch as Googleでちゃんとレンダリングされていた。<br /> 途中でAngularのバージョンをあげたのでそのあたりが原因かもしれない。</p> <h3 id="原因の特定"><a href="#%E5%8E%9F%E5%9B%A0%E3%81%AE%E7%89%B9%E5%AE%9A">原因の特定</a></h3> <p>今回は面倒だったので特定せずにCakePHPのみにした。</p> <p>JavaScriptを使い、tryでエラーをcatchできるので、それで試してみると良い、とどこかに書かれていた。<br /> 結局クローラアクセスの場合だけ出るエラーなどがJavaScript上にある場合、こうなってしまうのかもしれない。<br /> JavaScriptフレームワークでサイトを構築するときに気をつけなければならない点のようだ。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14265 2017-02-22T00:47:33+09:00 2017-02-22T00:47:33+09:00 https://crieit.net/posts/Angular2-wercker-CI Angular2プロジェクトをwerckerで無料CI <p>Angular2のプロジェクトをwerckerで無料CIした時の設定ログ。</p> <p>angular-cliのng testを使用。</p> <h3 id="要件"><a href="#%E8%A6%81%E4%BB%B6">要件</a></h3> <p>下記を満たすDockerイメージが必要となる。</p> <ul> <li>node7が入れられる</li> <li>chromium-browserが入っている</li> </ul> <h3 id="Dockerイメージ"><a href="#Docker%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8">Dockerイメージ</a></h3> <p>要件を満たすものを探してみたけどうまく見つからなかったので作成した。</p> <p><a target="_blank" rel="nofollow noopener" href="https://hub.docker.com/r/dala00/chromium-xvfb-angular-cli/">https://hub.docker.com/r/dala00/chromium-xvfb-angular-cli/</a></p> <h3 id="wercker.yml"><a href="#wercker.yml">wercker.yml</a></h3> <p>多分下記が最小。</p> <pre><code class="yaml">box: dala00/chromium-xvfb-angular-cli build: steps: - npm-install - script: name: test start code: | ng test --single-run </code></pre> <p>Dockerfileも小さいので別のnodeのバージョンのものが欲しい場合もすぐ作成できると思う。<br /> (今回のも同様にして作った)</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14266 2017-02-20T06:12:40+09:00 2017-02-20T06:12:40+09:00 https://crieit.net/posts/Codeship-Angular2-CI CodeshipでAngular2の無料CI <p>CodeshipでAngular2プロジェクトの無料CIの設定方法。</p> <p>Setup Commands</p> <pre><code class="bash">nvm install 7.0 npm install -g npm@latest npm install @angular/cli npm install npm list --depth=0 </code></pre> <p>Configure Test Pipelines</p> <pre><code class="bash">ng test --single-run </code></pre> <p>ng testはファイルの変更を検知して永久にテストをしてしまうのでsingle-runオプションが必要。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14267 2017-02-19T05:41:26+09:00 2018-06-23T23:21:56+09:00 https://crieit.net/posts/Angular2 Angular2のテスト時エラー備忘録 <p>Angularでng testを行った時に色々とエラーが出るが、<br /> 検索するとだいたい決まりきったわけのわからない解決方法があり、<br /> 何度も調べたりすることになるのでメモっておくことにする。</p> <p>随時更新。</p> <blockquote> <p>ngModel</p> </blockquote> <p>ngModelでエラーの場合はFormsModuleをimports。(app.module.ts参照)</p> <blockquote> <p>No provider for Overlay!</p> </blockquote> <pre><code class="typescript">import {OVERLAY_PROVIDERS} from "@angular/material"; </code></pre> <pre><code class="typescript">providers: [OVERLAY_PROVIDERS], </code></pre> <blockquote> <p>Error: Error in ./MyComponent class MyComponent - inline template:5:8 caused by: Cannot read property 'subscribe' of undefined</p> </blockquote> <p>template:5:8は見てみるとa routerLinkのところ。下記のRouterLinkStubDirectiveをdeclarationsに追加すればいい。</p> <p><a target="_blank" rel="nofollow noopener" href="https://angular.io/docs/ts/latest/guide/testing.html#!#router-link-stub">https://angular.io/docs/ts/latest/guide/testing.html#!#router-link-stub</a></p> <p>もしrouterLinkを動作させるためにRouterTestingModule, RouterModuleやアプリケーションのルーティングモジュールなどをimportsしている場合は外す。</p> <h3 id="モック"><a href="#%E3%83%A2%E3%83%83%E3%82%AF">モック</a></h3> <p>本番と同じ動作をさせられない場合はモックを使う。</p> <p><a target="_blank" rel="nofollow noopener" href="http://alphabrend.hatenablog.com/entry/2017/02/03/095213">Angular2でコンポーネントのユニットテストを書いてみた - アルファブレンド プログラミングチップス</a></p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14268 2017-02-17T17:57:57+09:00 2018-09-24T14:10:31+09:00 https://crieit.net/posts/angular-cli-AoT angular-cliでAoTによる高速化 <p>Angular2はAoTというものがあり、動作を高速化することができる。</p> <p>他の記事で色々設定が必要というものを見かけるが、angular-cliを使っている場合は元々機能があるのですぐ有効化することができる。</p> <pre><code class="bash">ng build --prod --aot </code></pre> <p>で有効化できるし、そもそも最新のangular-cliだとデフォルトで有効化されているため --aot オプションは不要。</p> <p>Angular2.2から2.4にしてangular-cliも最新にしてみたところ、元々ビルドされたmain.jsが90MBほどあったものが800kBほどに最適化された。<br /> スマホで10秒近くかかっていた初期化も改善された。</p> <p>古いバージョンを使っている人は早めに最新バージョンに変更した方が良い。</p> <p>ただ、色々と別のパッケージを使っていると思うが、それらはバージョンが合わないと動作しなかったりする。<br /> 自分もng2-tag-input0.8.5だと動かないので0.8.0にしたら動作したし、<br /> ネット上の情報だと他にも同様のエラーがでるパッケージがある。<br /> 色々とバージョンの調整は必要。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14270 2017-02-13T22:31:19+09:00 2018-08-19T14:12:10+09:00 https://crieit.net/posts/Angular2-5b0d188ca34ca Angular2アプリケーションを通常のサーバーにデプロイ <p>Angular2アプリケーションをangular-cliでビルドすると公開用のdistフォルダが作成されるので、<br /> 基本的にはこれをサーバーにアップすればそのまま動作する。</p> <p>ただ、jsファイルはハッシュ値がついてファイル名が変わってしまうため、<br /> 多少気をつけないといけない。</p> <p>簡単にデプロイするための方法として下記のような方法があげられる。</p> <h3 id="distフォルダもignoreせずバージョン管理してしまう"><a href="#dist%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%82%82ignore%E3%81%9B%E3%81%9A%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%AE%A1%E7%90%86%E3%81%97%E3%81%A6%E3%81%97%E3%81%BE%E3%81%86">distフォルダもignoreせずバージョン管理してしまう</a></h3> <p>特に支障がなければdistフォルダもcommitしてしまえば良いと思う。</p> <p>ソースに変更がなければ何度ビルドしてもハッシュ値は変わらない気がするので、<br /> バージョンアップの際だけビルドしてそのままコミットで問題ないと思う。<br /> あとは本番サーバーでpullするだけ。</p> <h3 id="デプロイ用のプログラムを作成する"><a href="#%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E7%94%A8%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B">デプロイ用のプログラムを作成する</a></h3> <p>何らかの理由でdistフォルダ以外は本番にアップしたくない場合、<br /> 上記方法は使えないので自動デプロイ用のプログラムを用意する必要がある。</p> <p>具体的には下記のような処理のプログラム。</p> <ol> <li>準備用フォルダを作成</li> <li>準備用フォルダに最新のdist内ファイルを全てアップロード</li> <li>本番フォルダと準備用フォルダを入れ替え</li> </ol> <p><a target="_blank" rel="nofollow noopener" href="https://mokumoku.alphabrend.com/">一人もくもく会</a> 用にぱぱっと適当に作成したプログラムのサンプル。</p> <p><a target="_blank" rel="nofollow noopener" href="https://gist.github.com/dala00/7a586b0c47829ca1c9b879ddf67dd344">Deploying script with sftp for Angular. 'npm run deploy' or 'npm run deploy rollback' · GitHub</a></p> <p>必要に応じて準備用フォルダを事前に削除したり、古い本番フォルダを残してバージョン管理するなり削除するなりが必要かと思われる。</p> <h3 id=".htaccess"><a href="#.htaccess">.htaccess</a></h3> <p>関係ないので補足になるが、ルーティングを使っている場合、トップページ以外からアクセスが来た場合もそのURLのページを表示しなければならないので、<br /> 下記のような.htaccessの設定が必要となる。</p> <pre><code class="bash">RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] </code></pre> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14271 2017-02-12T05:53:12+09:00 2018-10-25T12:50:27+09:00 https://crieit.net/posts/Angular2-CakePHP3 Angular2とCakePHP3を共存させる <p>AngularとCakePHPを共存、つまり同じホスト名で動作させたい場合。<br /> 例えば下記のように隣同士で並んでいるとする。<br /> Angularはビルドしたdistフォルダのみの公開でその他のソースはアップなどはしない場合。</p> <ul> <li>app</li> <li>dist</li> </ul> <p>公開フォルダはAngular側のdistフォルダにするが、<br /> AngularもCakePHPもルーティングが必要になるので、distフォルダ内の.htaccessで両方動作するように設定を行う。</p> <p>CakePHP側は、全てapiというprefix内にプログラムを入れることで振り分けが容易となる。</p> <pre><code class="bash">RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_URI} ^/api/ RewriteRule ^ index.php [L] RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] </code></pre> <p>index.phpはCakePHPのwebrootのもののパス部分の記述だけを修正。下記の2箇所。</p> <pre><code class="php">require dirname(__DIR__) . '/app/vendor/autoload.php'; </code></pre> <pre><code class="php">$server = new Server(new Application(dirname(__DIR__) . '/app/config')); </code></pre> <p>index.phpと.htaccessはAngularの開発時のsrcフォルダに入れておき、<br /> angular-cli.jsonのapps.assetsの設定に含めておけば良い。</p> <p>こういった方法であればホスト名も同じにできるので、SSLを2つ分とったり、などという手間をかける必要がなくなる。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14272 2017-02-11T01:22:31+09:00 2018-10-18T01:18:48+09:00 https://crieit.net/posts/f740e34f70d01a0feec3c4c60a66392f 一人もくもく会というサービスを作成 <p>一人もくもく会というサービスを作成して公開した。</p> <p><a target="_blank" rel="nofollow noopener" href="https://mokumoku.alphabrend.com/">一人もくもく会</a></p> <h3 id="概要"><a href="#%E6%A6%82%E8%A6%81">概要</a></h3> <p>世の中誰でも夜暇な時に適当にプログラミングをあれこれ試す時があると思うが、<br /> そういった時のログを投稿できるサービス。</p> <p>Qiitaやブログのようにきっちりプログラムや記事を完成させなくても、<br /> 適当にどんどんその日毎のログを残すためのもの。</p> <h3 id="フレームワーク"><a href="#%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF">フレームワーク</a></h3> <ul> <li>Angular</li> <li>CakePHP3</li> </ul> <p>デザインはとりあえずAngular MaterialやMaterial Design Liteをごちゃごちゃに使っている。<br /> できればAngular Materialのみでやりたかったが、こちらは現在betaで開発中のため色々足りない。<br /> 他のあちらこちらから色々使えるパーツを探してきて使う必要がある。</p> <h3 id="現状"><a href="#%E7%8F%BE%E7%8A%B6">現状</a></h3> <p>とりあえず必要最低限以下の機能を作成しただけなので、αバージョン。<br /> 誰でもすぐGithubアカウントかTwitterアカウントでログインできるので、<br /> 気が向いた方は使っていただける状態。<br /> 0円でSSLもつけているので。</p> <h3 id="今後"><a href="#%E4%BB%8A%E5%BE%8C">今後</a></h3> <p>作成は進めていくが、せっかくなのでその開発ログも実際にサービス上に残していく予定。<br /> 誰にも利用されなくてもデータが増えていくというのは一石二鳥だ。</p> <h3 id="その他補足色々"><a href="#%E3%81%9D%E3%81%AE%E4%BB%96%E8%A3%9C%E8%B6%B3%E8%89%B2%E3%80%85">その他補足色々</a></h3> <h4 id="マークダウン"><a href="#%E3%83%9E%E3%83%BC%E3%82%AF%E3%83%80%E3%82%A6%E3%83%B3">マークダウン</a></h4> <p>投稿はmarkdownで可能。<br /> Github色のシンタックスハイライトも入れてある。</p> <h4 id="SPA"><a href="#SPA">SPA</a></h4> <p>Angularを使っているのでSPAとなっている。<br /> 面倒なのでサーバーサイドレンダリングはしていない。<br /> とりあえずGoogleのクローラに全部お任せ。<br /> きっとそのうちAngular自体がデフォルトでUniversal対応してくれるだろう。</p> <h4 id="Google Analytics"><a href="#Google+Analytics">Google Analytics</a></h4> <p>SPA用にAutotrackというのがあるのでそれを使った。動いているかは不明。</p> <h4 id="ソーシャルシェア、ブックマーク"><a href="#%E3%82%BD%E3%83%BC%E3%82%B7%E3%83%A3%E3%83%AB%E3%82%B7%E3%82%A7%E3%82%A2%E3%80%81%E3%83%96%E3%83%83%E3%82%AF%E3%83%9E%E3%83%BC%E3%82%AF">ソーシャルシェア、ブックマーク</a></h4> <p>投稿データにシェア、ブックマークボタンをいくつか入れてみた。<br /> SPA用に調整してあるので多分動くと思うがまだ記事が0なので本番では未確認。<br /> うまく動かなかったら投稿しつつ修正していく。</p> <h4 id="タグ"><a href="#%E3%82%BF%E3%82%B0">タグ</a></h4> <p>タグ機能があり自由にタグを追加できるので、<br /> イベントタグを作ってみんなで参加、ということも可能。<br /> これでオフラインもくもく会を流行らせたい。</p> <h4 id="ソース管理"><a href="#%E3%82%BD%E3%83%BC%E3%82%B9%E7%AE%A1%E7%90%86">ソース管理</a></h4> <p>非公開なのでBitBucket。CakePHP3のCIはCodeship。<br /> Angularは元々テストでエラーが出まくってしまうのでエラーを取り切ってから対応予定。</p> <h4 id="不具合"><a href="#%E4%B8%8D%E5%85%B7%E5%90%88">不具合</a></h4> <p>いくつかある。早めに必要な機能などもある。掲載しつつ修正していく。</p> <h4 id="デプロイ"><a href="#%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4">デプロイ</a></h4> <p>distフォルダ毎サーバーにアップすれば良いのだが、<br /> それだけでも毎回面倒なのでデプロイ用のプログラムを作る必要がある。</p> <p>ただ、各ファイルのハッシュ値はソースを変更しなければ毎回同じっぽいので、<br /> dist毎pushしてしまえばサーバー側はpullだけでもいいかもしれない。</p> <p>ちなみに、distディレクトリにCakePHP用のindex.phpが入っていて、.htaccessでCakePHP側とAngular側を振り分けている。<br /> またこの詳細は別記事に書く。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14274 2017-02-03T18:52:13+09:00 2018-10-02T10:46:43+09:00 https://crieit.net/posts/Angular2-5b0d1890984f9 Angular2でコンポーネントのユニットテストを書いてみた <p>Angularのコンポーネントのユニットテストを書いてみた。<br /> TestBedを使用しているパターン。</p> <p>angular-cliでファイルを作成しつつ、<br /> アプリケーションをある程度書いてng testしてみると大量にエラーが出るので、<br /> それらをいくつかエラーが出ないように修正してみた。</p> <h3 id="エラーが出る原因"><a href="#%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E5%87%BA%E3%82%8B%E5%8E%9F%E5%9B%A0">エラーが出る原因</a></h3> <p>基本的には、htmlで使用されているコンポーネントや、<br /> ts内で使用されているサービスなどの依存関係が満たされていないため。</p> <p>アプリケーション実行時はmoduleの設定などで満たされているが、<br /> テストは各テストで別途設定してあげなければならない。</p> <p>テストは別途設定にすることで、各サービスなどはmockを使用できるようになっている。</p> <h3 id="テスト例"><a href="#%E3%83%86%E3%82%B9%E3%83%88%E4%BE%8B">テスト例</a></h3> <p>ユーザー情報を取得して表示するだけのページのコンポーネント例。<br /> コンポーネント側ではActivatedRouteからidを取得し、<br /> UserServiceでそのidからhttpでユーザー情報であるUserを取得し、<br /> Userをコンポーネント上で表示するだけの例。</p> <pre><code class="typescript">/* tslint:disable:no-unused-variable */ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ActivatedRouteStub } from '../../../../testing/router-stubs'; import { UserServiceStub } from '../../../../testing/user-service-stub'; import { UserDetailComponent } from './user-detail.component'; import { UserService } from '../../../services/user.service'; import { User } from '../../../models/user'; describe('UserDetailComponent', () => { let component: UserDetailComponent; let fixture: ComponentFixture<UserDetailComponent>; let activatedRoute = new ActivatedRouteStub(); let userService = new UserServiceStub(); let user = new User(); beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ UserDetailComponent ], providers: [ {provide: ActivatedRoute, useValue: activatedRoute}, {provide: UserService, useValue: userService} ], }) .compileComponents(); activatedRoute.testParams = {id: 1}; userService.user = user; })); beforeEach(() => { fixture = TestBed.createComponent(UserDetailComponent); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); it('user set', () => { expect(component.user && component.user == user).toBeTruthy(); }); }); </code></pre> <h4 id="declarations"><a href="#declarations">declarations</a></h4> <p>html上に表示するコンポーネントはここで設定。<br /> 他のコンポーネントを使っている場合はここに追記。</p> <h4 id="providers"><a href="#providers">providers</a></h4> <p>サービスなどの設定。provideで実際のクラスを指定し、useValueでモックを指定できる。</p> <h3 id="モック"><a href="#%E3%83%A2%E3%83%83%E3%82%AF">モック</a></h3> <p>router-stubs.tsは下記で書かれたものを改造したりして使用。</p> <p><a target="_blank" rel="nofollow noopener" href="https://angular.io/docs/ts/latest/guide/testing.html">Angular Docs</a></p> <p>Observableを使用しているのでクラスにまとめた方が使いまわしやすい、ということ。<br /> providersではそれらのモックを使用し、compileComponentでコンポーネントが構築された後、</p> <pre><code class="typescript"> activatedRoute.testParams = {id: 1}; userService.user = user; </code></pre> <p>で返すべき値をセットしている。<br /> 上記はgetメソッドになっているので、セットされるとコールバックが起動されて処理が進んでいく。<br /> あとは自由にitで確認していくだけ。</p> <p>適当にぱぱっとエラーを消して処理を追加しただけなので全体的に正しいかどうかは不明。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14276 2017-01-27T22:54:55+09:00 2018-10-04T14:39:47+09:00 https://crieit.net/posts/Angular2-5b0d1890b7c78 Angular2でマークダウンエディタを使うディレクティブ <p>Angular2で下記のシンプルなマークダウンエディタを動作させるためのディレクティブを作ってみた。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/NextStepWebs/simplemde-markdown-editor">GitHub - nextstepwebs/simplemde-markdown-editor</a></p> <p>シンプルとはいえ、プレビューや、全画面表示によるプレビューを見ながらの編集、<br /> ツールバーにカスタムボタンを追加など、結構機能が充実していると思う。<br /> Fork数なども多い。</p> <pre><code class="typescript">import { Directive, ElementRef } from '@angular/core'; const SimpleMDE: any = require('simplemde'); @Directive({ selector: '[appSimplemde]' }) export class SimplemdeDirective { mde: any; constructor(private el: ElementRef) { } ngAfterViewInit() { this.mde = new SimpleMDE({ element: this.el.nativeElement, renderingConfig: { codeSyntaxHighlighting: true, }, }); } } </code></pre> <pre><code class="html"><textarea appSimplemde [(ngModel)]="body" ...></textarea> </code></pre> <p>ちなみに、下記のngModelを使う方法がディレクティブでも可能なよう。</p> <p><a target="_blank" rel="nofollow noopener" href="http://alphabrend.hatenablog.com/entry/2017/01/02/233403">Angularで自作コンポーネントのngModel双方向バインディング - アルファブレンド プログラミングチップス</a></p> <p>上記実装後、下記の行を加えておけば呼び出し元の値が連動する。</p> <pre><code class="typescript"> this.mde.codemirror.on('change', () => { this.propagateChange(this.mde.value()); }); </code></pre> <p>既存データの編集機能も必要ならwriteValueも実装したり等。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14277 2017-01-24T06:43:08+09:00 2018-11-27T14:13:58+09:00 https://crieit.net/posts/Angular2-Shared-Data Angular2で共通データの管理(Shared Data) <p>※古い記事のため主にRxJSの説明になっています。共通データを管理したい場合はstoreを使いましょう。</p> <hr /> <p>Angularにて、アプリケーション全体で共通のデータを利用したいことなどがある。<br /> 例えばログインしているユーザーの情報など。</p> <h3 id="ダメな例"><a href="#%E3%83%80%E3%83%A1%E3%81%AA%E4%BE%8B">ダメな例</a></h3> <p>そこで共通データを管理するSharedDataService等を作る場合、<br /> 何も考えないと下記のようになると思う。</p> <pre><code class="typescript">export class SharedDataService { data: any; constructor() { data = {}; } set(key: string, value: any) { this.data[key] = value; } get(key: string) { return this.data[key]; } } </code></pre> <p>各コンポーネントからは下記のようにデータを取得。</p> <pre><code class="typescript">const user = this.sharedDataService.get('user'); </code></pre> <p>しかしこれはうまくいかない。</p> <p>なぜかというと、だいたいログイン情報のようなものは非同期で取得して来ると思う。<br /> その際にsetで値を保存すると思うが、その時はすでに各コンポーネントのonNgInit等も完了してしまっているし、<br /> コンポーネントのプロパティに値を渡しているわけでもないので全体的に再描画はされない。</p> <h3 id="成功例"><a href="#%E6%88%90%E5%8A%9F%E4%BE%8B">成功例</a></h3> <p>RxJSを使ってSharedDataService内のデータが変わったことを通知する仕組みにする必要がある。</p> <pre><code class="typescript">export class SharedDataService { data: any; updateSources: any; syncs: any; constructor() { data = {}; updateSources = {}; syncs = {}; } set(key: string, value: any) { this.data[key] = value; if (this.updateSources[key]) { this.updateSources[key].next(value); } } sync(key: string, callback: (data: any)=>void) { if (!this.syncs[key]) { const updateSource = new Subject<any>(); this.updateSources[key] = updateSource; this.syncs[key] = updateSource.asObservable(); } this.syncs[key].subscribe(result => callback(result)); if (this.data[key] !== undefined) { callback(this.data[key]); } } } </code></pre> <p>データを取得する各コンポーネント側では下記のようにする。</p> <pre><code class="typescript">this.sharedDataService.sync('user', user => this.user = user); </code></pre> <p>これでどこかで値がsetされる度に各コンポーネントの値が更新されて再描画されていく。</p> <h3 id="応用例"><a href="#%E5%BF%9C%E7%94%A8%E4%BE%8B">応用例</a></h3> <p>この仕組みを利用するとtitleタグなどの書き換えも簡単にできる。<br /> setTitleはどうもAppComponent上でしか動作しないようなので、まずAppComponentにて</p> <pre><code class="typescript">this.sharedDataService.sync('title', this.titleService.setTitle(title)); </code></pre> <p>ルーティングの各コンポーネントで</p> <pre><code class="typescript">this.sharedDataService.set('title', article.title); </code></pre> <p>そしてtitleをsetしていないページではtitleが元に戻るように、AppComponentにて</p> <pre><code class="typescript">this.router.events.subscribe((event) => { if (event instanceof NavigationStart) { this.data.set('title', null); } }); </code></pre> <p>これで指定したページでだけtitleが書き換えられる負担の少ない処理が可能となる。</p> <h3 id="補足"><a href="#%E8%A3%9C%E8%B6%B3">補足</a></h3> <p>ざっと作ったのでもしかするともうちょっと一般的なやり方があるかもしれないし、<br /> 構文も間違っている箇所があるかもしれない。</p> <p>syncはコールバックの利用でなくObservableをそのままreturnした方が良いのかもしれない。<br /> ただ、元々データが存在した場合はすぐ値がほしいので、<br /> それを考慮するとコールバック形式である必要があるかもしれないしObservableでちゃんとしたやり方があるかもしれない。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14280 2017-01-03T08:34:03+09:00 2018-10-23T17:12:57+09:00 https://crieit.net/posts/Angular-ngModel Angularで自作コンポーネントのngModel双方向バインディング <p>Angularはinputタグ等のform用タグにて[(ngModel)]属性を使用すると双方向バインディングになる便利な機能がある。</p> <p>これを自作した独自のコンポーネントで実現する方法。</p> <p>簡単に言えば下記の解説通り。</p> <p><a target="_blank" rel="nofollow noopener" href="http://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html">Custom Form Controls in Angular by thoughtram</a></p> <p>ざっと説明すると下記の通り。</p> <h3 id="ControlValueAccessorインターフェイスを使用する"><a href="#ControlValueAccessor%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%82%A4%E3%82%B9%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B">ControlValueAccessorインターフェイスを使用する</a></h3> <p>コンポーネントにControlValueAccessorをimplementする。</p> <h4 id="writeValue"><a href="#writeValue">writeValue</a></h4> <p>プロパティとして渡された値が来るので処理。</p> <h4 id="registerOnChange, registerOnTouched"><a href="#registerOnChange%2C+registerOnTouched">registerOnChange, registerOnTouched</a></h4> <p>changeとtouchedのコールバック関数が渡されるので、<br /> それを保存しておいてコンポーネントの呼び出し元に返したい時に結果を返す。</p> <h3 id="providers"><a href="#providers">providers</a></h3> <p>Angularにきちんと認識させるためにNG_VALUE_ACCESSORのprovidersを設定しているらしい。</p> <h3 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h3> <p>上記のような感じでできる。<br /> 共通設定などを一切汚さずコンポーネントのみで解決できるところが良い。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14287 2016-11-28T22:45:33+09:00 2016-11-28T22:45:33+09:00 https://crieit.net/posts/Angular2-universal-starter-angular-material2 Angular2のuniversal-starterでangular/material2が使えない <p>Angular2はuniversal-starterから始めることで簡単にサーバー再度レンダリングができるが、<br /> angular/material2を入れてみようとしたところ、<br /> どうもエラーが出てうまく動かない。</p> <p>検索してみると、どうも今はちゃんと動かないようだ。(2016-11-28現在)<br /> githubのissuesをみるとみんなで解決しようとしている途中だった。</p> <p>(そもそもangular/material2はアルファバージョンだった)</p> <p>適当にアプリケーションを作ろうと思ったが、周辺環境がもうちょっと整うまでは様子見しようと思う。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14288 2016-11-26T02:25:46+09:00 2018-10-24T16:13:50+09:00 https://crieit.net/posts/Angular2-Django Angular2アプリを全部無料で公開してみる-Django編 <p>Angular2で開発したアプリケーションを完全に無料で公開できる方法を考えてみた。</p> <h3 id="要件"><a href="#%E8%A6%81%E4%BB%B6">要件</a></h3> <p>上から順に重要度が高い。</p> <ul> <li>Angular2</li> <li>Angular2のサーバーサイドレンダリング対応</li> <li>そこそこのDB容量</li> <li>なるべく無料枠が大きいところ</li> <li>開発しやすさ</li> </ul> <h3 id="考察"><a href="#%E8%80%83%E5%AF%9F">考察</a></h3> <p>まず、Angular2をサーバーサイドレンダリングしようと思うと、node.jsでサーバーを動作させることが必要となる。<br /> これは色々調べてみると、恐らく速度や無料枠を比較するとherokuがベストかと思う。<br /> 2016年現在は無料で停止なしで稼働できる。</p> <p>上記は確定っぽいのでDB側を考えてみる。</p> <p>容量の無料枠で一番大きいのは恐らくAmazon DynamoDBの25GB。</p> <p>様々な言語のSDKがあるのでどのサーバーでも行けると思う。<br /> Angular2からも直接行けるが接続情報が筒抜けになるし、直接DB接続だと複数の処理を1リクエストにまとめたりができないので、<br /> 費用が発生する可能性が高くなる。<br /> やはり一度サーバーを経由したいところ。</p> <p>Angular2 → Amazon lambda → Amazon DynamoDB</p> <p>というのもなかなか良さそう。<br /> ただし認証によってアクセスできる処理をきっちり整理する必要がある。<br /> こちらはまた今後確認してみたい。</p> <p>(追記)<br /> 調べてみたらcognito + lambda + DynamoDBを使用する必要がありそう。<br /> ちょっとこれはめんどそうだしcognitoは未認証ユーザーという概念があるが、<br /> もしそれも課金計算に含めるなら費用が発生する可能性は高くなりそう。</p> <h3 id="構成"><a href="#%E6%A7%8B%E6%88%90">構成</a></h3> <p>今回は総合的なバランスを考えて下記を試してみた。</p> <p>Angular2 → GAE (Python + Django) + Datastore</p> <ul> <li>直接APIサーバーにアクセスするだけなのでサーバーを分けない場合とアクセス時間が変わらない。</li> <li>Datastoreが1GB(?)無料なのでそこそこ。</li> <li>Djangaeを使うとDjangoのモデルそのままでDatastoreにアクセスできるので、<br /> この環境用の特別なプログラムで開発をする必要がない。</li> <li>pythonはpython, python3, pip, pip3と分けてインストールされたり切り替えたりができたりするので、<br /> python2しか使えないGAEでもローカルの開発環境を汚さずに開発しやすい。</li> <li>pythonはリモートで本番のDjango用のコマンドを実行できるのでマイグレーションなども簡単。</li> </ul> <h3 id="Angular2側"><a href="#Angular2%E5%81%B4">Angular2側</a></h3> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/angular/universal-starter">GitHub - angular/universal-starter: Angular 2 Universal starter kit by @AngularClass</a></p> <p>ng newしないで、上記をそのままcloneして改造していくのがいい。<br /> デフォルトのコマンドでherokuでそのまま動くし、<br /> Visual Studio Codeでもデバッグできる。</p> <p>必要であればangular-cliで新規作成したプロジェクトから必要なファイルだけコピーしてくると良いと思う。</p> <h3 id="GAE側"><a href="#GAE%E5%81%B4">GAE側</a></h3> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/ottoyiu/django-cors-headers">GitHub - ottoyiu/django-cors-headers: Django app for handling the server headers required for Cross-Origin Resource Sharing (CORS)</a></p> <p>別サーバーなのでこれをいれておけば動く。<br /> いちいち全部のResponseにヘッダーを指定する必要はない。</p> <p>接続や設定などはGAEの特別な仕様などがあり最初はつまずくが、<br /> 解決すればあとは普通と同じように開発ができる。</p> <p>チュートリアルで操作させられるが、どうもGithubと連携できる開発環境みたいなのもあるようだ。</p> <h3 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h3> <p>たいしてアクセスやデータ量の無いアプリケーションは、こんな感じで無料でなるべく開発しやすい環境を模索すると面白そうだ。</p> <p>APIサーバー側は、さくらレンタルなど安いサーバーを別途持っていればそれをそのまま使うのも簡単だ。</p> だら@Crieit開発者 tag:crieit.net,2005:PublicArticle/14309 2016-06-04T00:14:50+09:00 2018-10-15T21:48:36+09:00 https://crieit.net/posts/Angular2-loading Angular2のフルスクリーンloading表示コンポーネント <p>Angular2用で何か処理をする間に<br /> オーバーレイでloadingを表示するコンポーネントの作成。</p> <p>[https://gist.github.com/02517becac0c18215c71753773b74e07:embed#Angular2 fullscreen loading component](https://gist.github.com/02517becac0c18215c71753773b74e07:embed#Angular2 fullscreen loading component)</p> <p><a target="_blank" rel="nofollow noopener" href="https://gist.github.com/02517becac0c18215c71753773b74e07">Angular2 fullscreen loading component</a></p> <h3 id="使い方"><a href="#%E4%BD%BF%E3%81%84%E6%96%B9">使い方</a></h3> <p>読み込む</p> <pre><code class="javascript">import { LoadingComponent } from "./loading.component"; </code></pre> <p>ディレクティブ指定</p> <pre><code class="javascript">directives: [LoadingComponent] </code></pre> <p>テンプレート内</p> <pre><code class="javascript"><loading [loading]="isLoading"></loading> </code></pre> <p>プロパティ</p> <pre><code class="javascript">isLoading: boolean = false; </code></pre> <p>表示、非表示</p> <pre><code class="javascript">// 表示 this.isLoading = true; // 非表示 this.isLoading = false; </code></pre> だら@Crieit開発者