ionic6 + react のはじめ方

● ionicのインストール

npm install -g @ionic/cli

Ionic, react , typescript のブランクアプリを作成

ionic start client-app blank --type react

GUIを使ってメニューから選択したい場合はこちらのコマンドを実行します

ionic start

後は画面上からいろいろ選択するだけでokです。

フレームワークは react , angular , vue.js から選択できます。

No.2198
08/05 14:49

edit

angular Observable を返す

● angularでObservable を返す

普通のメソッド

protected myFunction(): boolean {
    return true;
}

  ↓ Observable を返すようにします

Observable を返すメソッド

import { forkJoin, timer, of, Observable } from 'rxjs';
/**
 * @returns Observable
 */
protected myFunction(): Observable<boolean> {
    return of(true);
}

呼び方

this.myFunction.subscribe(
  data => ..., // Promise.then
  err => ..., // Promise.catch
  () => ... // 終了時常に実行
);

● Subscriptionのかわりに Observable を返す

引用 : https://bit.ly/2K1RDFo

of(123456) で 値: 123456 を返す場合

/**
 * @returns Observable
 */
  protected myFunction(): Observable<any> {
    return of(123456).pipe(
      map((res: any) => {
        console.log("■ next ■")
        return res;
      }),
      catchError(err => {
        console.log('■ catchError 1 ■ caught mapping error and rethrowing', err);
        return throwError(err);
      }),
      finalize(() => {
        console.log("■ finalize ■")
      }),
      catchError(err => {
        console.log('■ catchError 2 ■caught rethrown error, providing fallback value');
        return of([]);
      }),
    );
}

結果(正常時)

■ next ■
■ finalize ■

ErrorObservable.create('error') でテスト的にエラーを発生させる場合

import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
/**
 * @returns Observable
 */
  protected myFunction(): Observable<any> {
    // エラーを発生させます
    return ErrorObservable.create('error').pipe(
      map((res: any) => {
        console.log("■ next ■")
        return res;
      }),
      catchError(err => {
        console.log('■ catchError 1 ■ caught mapping error and rethrowing', err);
        return throwError(err);
      }),
      finalize(() => {
        console.log("■ finalize ■")
      }),
      catchError(err => {
        console.log('■ catchError 2 ■caught rethrown error, providing fallback value');
        return of([]);
      }),
    );
}

結果(エラー時)

■ catchError 1 ■ caught mapping error and rethrowing error
■ catchError 2 ■caught rethrown error, providing fallback value
■ finalize ■
No.1933
12/16 13:20

edit

TypeScript の Parameter 'xxx' implicitly has an 'any' type に対応する

● TypeScript の Parameter 'xxx' implicitly has an 'any' type に対応する

let user = Users.find(user => user.id === query);

   ↓

let user = Users.find((user: any) => user.id === query); 
No.1930
12/10 14:06

edit

TypeScript で ドキュメントコメント JSDoc を記述する

● TypeScript で ドキュメントコメント JSDoc を記述する

型はメソッドの宣言に記述してあるのでコメント内では省略してもいいでしょう。

例:

/**
* 関数の説明
* @param arg 引数の説明
* @return 番号を返す
*/
public doSomething (arg: string) : number {
    //...
}
No.1919
01/06 09:43

edit

Angularで子コンポーネントに css を overrideする

● Angularで子コンポーネントに css を overrideする

.ts ファイル

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

encapsulation: ViewEncapsulation.None を使用します

.ts ファイル

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  encapsulation: ViewEncapsulation.None
})

export class HeaderComponent {

}

.scss ファイル

app-header {
  // your styles here and any child component styles can go here
}
No.1911
11/25 21:17

edit

実は簡単なAngularの双方向( two way )バインディング

● 実は簡単なAngularの双方向( two way )バインディング

@Input() value を作ってるならば
@Output() valueChange = new EventEmitter(); と、同名+ChangeのEventEmitterを作るだけでよい。
そうすると、[(value)] で双方向バインディング出来ます。

引用: https://qiita.com/kohashi/items/bcbcc9cbeaee9498e4fe

補足

バインディングしている変数やクラスに「変更があったとき」 @Output を経由して 変更が適用されるので、
バインディングしている変数へ「値を再代入して初期化」した場合には @Output を経由しないので注意が必要です。
// × 変更が適用されない
this.value = new MyClass();

// 〇 初期化するメソッドを自作して、メソッドを実行する
this.value.deleteAll();

● 自作コンポーネントでの双方向バインディングの方法

自作コンポーネント
@Inputでプロパティを定義する。
@OutputでEventEmitterを定義する。EventEmitterの型は@Inputの型と同じものとする。
@Output側のプロパティ名を@Inputのプロパティ名 + Changeにする。
例)@Inputがvalueだった場合、@OutputはvalueChange
自作コンポーネント内の処理で@Output側のEventEmitter.emit処理を実行することで、値が呼び出し側に伝搬する。
呼び出し側コンポーネント
[(双方向対象のプロパティ)]="呼び出し側プロパティ"のように呼び出す。

引用: https://kakkoyakakko2.hatenablog.com/entry/2018/08/24/003000

No.1910
12/17 08:59

edit

Angular で複数の Observable を待って処理する forkJoin を使用する

● Angular で複数の Observable を待って処理する forkJoin を使用する

import { forkJoin } from 'rxjs';
    forkJoin(
      this.service.myService01(),
      this.service.myService02()
    ).subscribe(
      data => {
        console.log( data[0] ); // myService01() の戻り値
        console.log( data[1] ); // myService02() の戻り値
      }
    );

戻り値は要求した順に返ってくるようです。  

https://bit.ly/3m9uWwQ

No.1909
11/25 09:45

edit

rxjs
Observable

angular で3桁ごとにカンマ区切りにする( php でいう number_format)

● angular で3桁ごとにカンマ区切りにする( php でいう number_format)

{{ 123456 | number }}

とすると、このようにカンマが入ります。

123,456
No.1908
11/24 10:51

edit

Angular の htmlファイル内で console.log () する

● Angular の htmlファイル内で console.log () する(方法1)

.ts

  protected console_log(val: string): void { console.log(val); }

.html

<my-component
    (change)="console_log( 'テストです' )"  
>

● Angular の htmlファイル内で console.log () する(方法2)

.ts

  private console: any = console;

.html

<my-component
    (change)="console.log( 'テストです' )"  
>
No.1904
11/17 14:56

edit

ViewChildの書き方

ts

export class AppComponent {
  @ViewChild('v1') protected countComponent: CountComponent;
  @ViewChild('v2') protected countComponent2: CountComponent;
}

html

  <div>
    <count #v1 [c]="100"></count>
    <button (click)="onClick1()">+</button>
  </div>
  <div>
    <count #v2 [c]="1"></count>
    <button (click)="onClick2()">+</button>
  </div>

.ts ファイルの 'v1' と .htmlファイルの #v1 で 同じコンポーネントが複数ある場合に識別します。

引用 : https://angular.keicode.com/basics/component-interaction-viewchild.php

No.1903
11/18 17:23

edit

Angularでhtmlエスケープをせずにhtmlをそのまま表示させる

● Angularでhtmlエスケープをせずにhtmlをそのまま表示させる

.ts

    this.myHtml= '<script>alert("XSS TEST");</script>テストHTML<br>テストHTML<br>テストHTML<br>テストHTML';

.html

    <p [innerHTML]="myHtml"></p>

これだけで、自動的にXSS対策もされています。

No.1899
11/10 15:21

edit

Angular の テンプレートシンタックス

● バインディングシンタックス

https://angular.io/guide/binding-syntax

日本語はこちらですが、日本語のほうがわかりにくいです。。。
https://angular.jp/guide/binding-syntax

Type Syntax Category
Interpolation
Property
Attribute
Class
Style
{{expression}} [target]="expression" bind-target="expression"
      
{{expression}}
[target]="expression"
bind-target="expression"
One-way
from data source
to view target
Event
(target)="statement" on-target="statement"
      

(target)="statement"
on-target="statement"
One-way
from view target
to data source
Two-way
[(target)]="expression" bindon-target="expression"
      
[(target)]="expression"
bindon-target="expression"
Two-way
No.1896
11/04 13:40

edit

Angular で httprequest のモックを json-server で作成する

● Angular のモックの種類

Angular でモックを作るなら ... 次の3つが浮かびます。

・1. Angular in-memory-web-api
参考: https://bit.ly/35iW0SN  

・2. json-server

・3. HttpClientTestingModule

・2. json-server を作成してみます。

● json-server を使用したモックの作成

2-1. json-serverのインストール

npm i -D json-server

2-2. db.json の作成

ファイル名は任意のファイル名でokですが、とりあえず db.json ファイルを新規作成します。

vi db.json

db.json を以下の内容で保存します。

{
    "users": [
        {
            "id": 1,
            "title": "お名前太郎",
        },
        {
            "id": 2,
            "title": "サンプル花子",
        },
        {
            "id": 3,
            "title": "検索太郎",
        }
    ]
}

2-3. package.json に設定を記述

( package.json がない場合はこちらを実行 )

npm init

package.json

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },

   ↓

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1" ,
    "json-server": "json-server --watch ./db.json --port 9999"
  },

2-4. サーバの実行

1. 通常の起動

npm run json-server

http://localhost:9999/ で json-server へアクセスすることができます。

2. オプションを指定した起動

npx json-server db.json -m middleware.js --watch --host 0.0.0.0 --port 9999

ホストに 0.0.0.0 を指定することで http://localhost:9999/http://ローカルIPアドレス で json-server へアクセスすることができます。

2-4. サーバへのリクエスト(GET)

http://localhost:9999/contents
http://localhost:9999/contents/1

にアクセスして戻り値を確認します。

2-4. サーバへのリクエスト(POST)

postmanを使って次のようにPOSTします。

postすると自動で db.json のファイルが更新されます。

db.json ファイルを更新しないようにするには

db.js

const db = require('./db.json')
module.exports = () => db

package.json

    "json-server": "json-server db.js --port 9999"

とすると、確かにjson-serverは更新されますが、メモリ上のみの更新なので db.json は更新されません。(再起動すると元のデータに戻ります。)

また、「ミドルウェアを使ってPOSTメソッドをGETメソッドに変換する」という技も有効ですのでそちらでもOKです。

middleware.js

module.exports = function (req, res, next) {
  if (req.method === 'POST') {
    req.method = 'GET'
    req.query = req.body
  }
next()
}
添付ファイル1
No.1884
11/27 14:08

edit

添付ファイル

Angular リアクティブフォームの基本

1. .tsファイル

↓これを追加

import { FormControl,Validators } from '@angular/forms';

  

export class AppComponent  {
}

  ↓ に変更

export class AppComponent  {
  public control = new FormControl('', [Validators.required]);
}

2. .htmlファイル

入力欄:<input type="text" [formControl]="control" required>
<div *ngIf="control.invalid && (control.dirty || control.touched)">
  <span *ngIf="control.hasError('required')">必須です。</span>
</div>

3. module.tsファイル

import {FormsModule, ReactiveFormsModule} from '@angular/forms';
  imports: [
    ....
    ReactiveFormsModule,  // 追加
  ],

どんなバリデーションがあるか?

class Validators {
  static min(min: number): ValidatorFn
  static max(max: number): ValidatorFn
  static required(control: AbstractControl): ValidationErrors | null
  static requiredTrue(control: AbstractControl): ValidationErrors | null
  static email(control: AbstractControl): ValidationErrors | null
  static minLength(minLength: number): ValidatorFn
  static maxLength(maxLength: number): ValidatorFn
  static pattern(pattern: string | RegExp): ValidatorFn
  static nullValidator(control: AbstractControl): ValidationErrors | null
  static compose(validators: ValidatorFn[]): ValidatorFn | null
  static composeAsync(validators: AsyncValidatorFn[]): AsyncValidatorFn | null
}

フォーカスが移った時にバリデーションを行いたい

  public control = new FormControl('', [Validators.required]);

  ↓ このように書き換える

  public control = new FormControl('', {
    validators: [Validators.required] ,
    updateOn: 'blur'
  });
No.1858
09/17 17:30

edit

Angular ルーティングとルーティングのデバッグ

● Angular ルーティング

次の ルーティングを指定します

/heroes
/users/home
/admin/home (lazyloading)
const routes: Routes = [
  { path: 'heroes', component: HeroesComponent } ,
  { path: 'users',
    children: [
      { path: 'home', component: HomeComponent },
    ]
  } ,
  { path: 'admin',
    children: [
          { path: '', loadChildren: './user-list/user-list.module#UserListPageModule' },
          { path: ':userId', loadChildren: './user-detail/user-detail.module#UserDetailPageModule' },
    ]
  } ,
];

● Angular ルーティングのデバッグ

src\app\app-routing.module.ts

imports: [ 
	RouterModule.forRoot(routes) 
],

  ↓   { enableTracing: true } を追加します。

imports: [ 
	RouterModule.forRoot(routes, { enableTracing: true }) 
],
No.1857
09/23 17:31

edit

d.ts の作成

https://bit.ly/2PJqsOS

>declarationスイッチをtrueにすると、全ての.tsファイルから.jsファイルと.d.tsファイルのペアを生成します。 >index.tsをコンパイルすると、index.jsとindex.d.tsを作ってくれる。 >そしてこのできたindex.d.tsをpackage.jsonで明らかにすればよい。

tsconfig.json

{
    "compilerOptions": {
        "outDir": "lib",
        "declaration": true,
    }
}
No.1835
08/11 13:36

edit

Angularでライブラリを作成して使用する

● Angularでライブラリを作成して使用する

Angular の機能を拡張するために新しいライブラリを作成して公開することができます。
同じ問題を複数のアプリで解決する必要があると判断した場合 (または他の開発者と解決策を共有したい場合)、それはライブラリの候補となります。

1. サンプルアプリを作成する

ng new libapp
cd libapp

2. 「アプリ」内に「ライブラリ」を作成する

ng generate library my-lib

ディレクトリ projects\my-lib が作成されてその中に src\lib が作成されてそこにソース一式が作成されます。

3. 「アプリ」内の「ライブラリ」内「コンポーネント」を作成する

ng g c components/button --project my-lib

4. 「アプリ」内の「ライブラリ」内「コンポーネント」をビルドする

projects\my-lib\src\public-api.ts に次を追加

export * from './lib/components/button/button.component';

projects\my-lib\src\lib\my-lib.module.ts を次のように変更

  exports: [MyLibComponent]

  ↓

  exports: [MyLibComponent,ButtonComponent]

ビルドの実行

ng build my-lib --watch

5. 「アプリ」内の「ライブラリ」内「コンポーネント」を使用する

src\app\app.component.ts で読み込ませる

import { ButtonComponent } from 'my-lib';

src\app\app.component.html を次の内容に変更

<h1>テスト</h1>
<lib-button></lib-button>

アプリの実行

ng serve --open
No.1830
08/11 09:15

edit

AngularでjQueryを使用する

● npmでインストールして使用する

・ 1. jquery をインストールする

npm install jquery --save

・ 2. jquery の型ファイルをインストールする

npm install --save jquery @types/jquery

プロジェクトフォルダのnode_modulesフォルダに@typesフォルダが作成され、jQueryの型定義ファイルがインストールされます。

・ 3. tsconfig.app.json で読み込んで使用する

types に jquery を追加

{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types" : [
      "jquery"
    ]
  },

・ 4. 使用する

src\app\app.component.ts

  toggleTitle(){
    const jqobj :JQuery = $(".title");
    jqobj.slideToggle().fadeOut();
  }

src\app\app.component.html

<h1 class="title" style="display:none">
  {{title}}
</h1>
<button (click)="toggleTitle()"> clickhere</button>

・ 5. アプリの実行する

 ng serve --open
No.1829
08/11 12:45

edit

子コンポーネントのデータを親コンポーネントへ渡す

● 子コンポーネントのデータを親コンポーネントへ渡す(基本)

1. 子コンポーネント ChildEditComponent で @Output() を宣言

子コンポーネント : ts

export class ChildEditComponent {
  @Output() childCreated = new EventEmitter<MyData>();

  onButtonClicked(): void {
    this.childCreated.emit(this.mydata);
  }
}

2. 親コンポーネント ParentEditComponent で @Output() を宣言

childCreated を受け取る

親コンポーネント : html

<my-edit-article (childCreated)="consoleShow($event)"></my-edit-article>

親コンポーネント : ts

export class ParentEditComponent {
  consoleShow(mydata: Mydata) {
    console.log( mydata );
  }
}

● 子コンポーネントのデータを親コンポーネントへ渡す(複数の引数を渡す)

一番いいのはモデルを作成してそのモデルを渡す方法ですが、次のように複数渡すこともできます。

子コンポーネント : ts

  @Output() childCreated = new EventEmitter<MyData>();

  ↓

  @Output() childCreated = new EventEmitter<{ id: number; mydata:MyData }>();
    this.childCreated.emit(this.mydata);

  ↓

    this.childCreated.emit({
        id: this.myid,
        mydata: this.mydata,
    });

親コンポーネント : ts

  consoleShow(mydata: Mydata) {
    console.log( mydata );
  }

  ↓

  consoleShow(childObj: any) {
    console.log( childObj.id );
    console.log( childObj.mydata );
  }

引用 : https://bit.ly/31YKrjD

No.1814
07/09 17:26

edit

Angularで2度押し禁止ボタンをカスタムディレクティブで作成する

● Angularで2度押し禁止ボタンをカスタムディレクティブで作成する

html

次のコンポーネントの HTML でボタンを次のようにします

<button type="button">送信する</button>

 ↓ ( appOnClickDisable="1" を追加 )

<button
    appOnClickDisable="1"
    type="button" >
    送信する
</button>

カスタムディレクティブを作成します app/directives/app-on-click-disable.directive.ts

import { Directive, HostListener, Input, Renderer2 } from '@angular/core';

 @Directive({
  selector: '[appOnClickDisable]'
})
export class AppOnClickDisableDirective {
  @Input() appOnClickDisable: number;
  constructor(
    private renderer: Renderer2, 
  ) { }
  @HostListener('click', ['$event']) onClick(event) {
    console.log( 'AppOnClickDisableDirective clicked' );
    if ( this.appOnClickDisable == 1 ){
      event.target.disabled = true;
    }
  }
}

app.module.ts で読み込みます app/app.module.ts

import { AppOnClickDisableDirective } from './directives/app-on-click-disable.directive';
@NgModule({
  declarations: [
    AppComponent,
    AppOnClickDisableDirective,  // 追加
  ],

以上で一度クリックするとボタンが disabled になります。 ( disabled解除は app-on-click-disable.directive.ts ソース内に実装する必要があります。)

No.1799
06/23 18:15

edit

Angular で environment が prod の時は console.log を出力しないようにする。

● Angular で environment が prod の時は console.log を出力しないようにする。

main.ts

if (environment.production) {
  enableProdMode();
}

  ↓ このように追加します

if (environment.production) {
  enableProdMode();
  // production環境下では console.log , console.error を何もさせない
  if (window) {
    window.console.log = () => {};
    window.console.error = () => {};
  }
}

引用元 : https://bit.ly/3hTy660

No.1798
06/23 17:56

edit

Angular renderer2 で直接DOM操作を行う。

● Angular renderer2 で直接DOM操作を行う。

https://angular.io/api/core/Renderer2

html

クリックイベントの引数に $event を渡します

<button
	type="button"
    (click)="sendButtonClicked($event)">
	送信する
</button>

ts

event.target が DOMオブジェクトです。

  private sendButtonClicked( event:any ) {
    // css class を追加
    this.renderer.addClass(event.target, 'now-loading');
  }
No.1797
06/23 17:56

edit

Angular で 前のページに戻る ( history.back() )

● Angular で 前のページに戻る ( history.back() )

my.component.ts に 以下の3つを追加

import { Location } from '@angular/common';
  constructor( 
              private location: Location
              ) {
  }
  private backBtnClick() {
    this.location.back();
  }

my.component.html に戻るボタンを設置

<button (click)="backBtnClick()" type="button">戻る</button> 
No.1795
06/22 15:23

edit

「AngularでREST API からデータ取得して一覧表示」の基本

● サービス BoardsService の作成

ng g service services/boards
CREATE src/app/services/boards.service.spec.ts (333 bytes)
CREATE src/app/services/boards.service.ts (135 bytes)
ng g コマンドでサービスを生成した場合、そのサービスは root に所属します。appモジュールではありません。

以下のように @Injectable に providedIn というのが追加になっていて、

@Injectable({
  providedIn: 'root'
})

どのモジュールから追加されるのか指定できるようになってます。
ここが 'root' の場合は app/app.module.ts への登録不要で Dependency Injection できます。
なお root 所属のサービスは全てのモジュールで同じインスタンスが利用されます(つまりシングルトン)。

引用: https://bit.ly/3d1U2bA

● app/app.module.ts に 外部モジュールの登録

import { HttpClientModule } from '@angular/common/http';
  imports: [
    .................................
    HttpClientModule,
  ],

● environments/environment.ts に 開発用 / 本番用 URL をセット

environments/environment.ts

export const environment = {
  production: false ,
  apiUrl: 'http://localhost:5000'
};

environments/environment.prod.ts

export const environment = {
  production: true ,
  apiUrl: 'http://localhost:5000'
};

● サービス「BoardsService」にロジックを記述

app/services/boards.service.ts を以下の内容で保存

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { environment } from './../../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class BoardsService {

  constructor(private httpClient: HttpClient) { }

  getIndex(): Observable<any> {
    return this.httpClient.get(environment.apiUrl + '/boards/');
  }
}

● コンポーネント「BoardsComponent」で一覧を表示

app/boards/boards.component.ts を以下の内容で保存

1. メンバ変数を定義

export class BoardsComponent implements OnInit {
  boards_loop = [];

2. DI に追加

  constructor(
               private boardsService: BoardsService ,
            ) 

3. ngOnInit() のタイミングでデータ取得

  ngOnInit() {
    this.boardsService.getIndex().subscribe(res => {
      this.boards_loop = res;
    });
  }

app/boards/boards.component.html に以下を追加

<ul>
<li *ngFor="let board of boards_loop">
    <span>{{board.id}}</span> : {{board.name}}
</li>
</ul>
No.1791
06/15 17:15

edit

NgModule の providers や imports の使い分け

● NgModule の providers や imports の使い分け

実は簡単な使い分け
declarations : ディレクティブ(含コンポーネント、パイプ)を書きます。 htmlテンプレートに書くもの、ですね。

providers : Serviceなど、DIで解決するものをここに書きます。 Angular 6 以降は各モジュールに
================
@Injectable({
  providedIn: 'root'
})
================
と書きます。

imports : 外部のAngularモジュール。Httpモジュールとか、UIモジュールとか。
これだけです!

引用元 : https://qiita.com/kohashi/items/1415a358901ca438c400

No.1790
06/15 17:11

edit

Angular 一覧表示の基本

● Angular 一覧表示の基本

app/app.component.ts

 ngOnInit() {
    this.boards_loop = [
      { id: 11, name: 'Mr. Nice' },
      { id: 12, name: 'Narco' },
      { id: 13, name: 'Bombasto' },
      { id: 14, name: 'Celeritas' },
      { id: 15, name: 'Magneta' },
      { id: 16, name: 'RubberMan' },
      { id: 17, name: 'Dynama' },
      { id: 18, name: 'Dr IQ' },
      { id: 19, name: 'Magma' },
      { id: 20, name: 'Tornado' }
    ];    
  }

app/app.component.html

<li *ngFor="let board of boards_loop">
    <span class="badge">{{board.id}}</span> : {{board.name}}
</li>

出力結果

<ul _ngcontent-bek-c0=""><!--bindings={
  "ng-reflect-ng-for-of": "[object Object],[object Object"
}--><li _ngcontent-bek-c0=""><span _ngcontent-bek-c0="">11</span> : Mr. Nice
</li><li _ngcontent-bek-c0=""><span _ngcontent-bek-c0="">12</span> : Narco
</li><li _ngcontent-bek-c0=""><span _ngcontent-bek-c0="">13</span> : Bombasto
</li><li _ngcontent-bek-c0=""><span _ngcontent-bek-c0="">14</span> : Celeritas
</li><li _ngcontent-bek-c0=""><span _ngcontent-bek-c0="">15</span> : Magneta
</li><li _ngcontent-bek-c0=""><span _ngcontent-bek-c0="">16</span> : RubberMan
</li><li _ngcontent-bek-c0=""><span _ngcontent-bek-c0="">17</span> : Dynama
</li><li _ngcontent-bek-c0=""><span _ngcontent-bek-c0="">18</span> : Dr IQ
</li><li _ngcontent-bek-c0=""><span _ngcontent-bek-c0="">19</span> : Magma
</li><li _ngcontent-bek-c0=""><span _ngcontent-bek-c0="">20</span> : Tornado
</li></ul>

app/app.component.html ( ng-container を使うやり方 )

    <ng-container *ngFor="let board of boards_loop">
        <li><span>{{board.id}}</span> : {{board.name}}</li>
    </ng-container>      

出力結果 ( ng-container を使うやり方 )

<ul _ngcontent-nve-c1="">
    <!--bindings={
  "ng-reflect-ng-for-of": "[object Object],[object Object"
     }-->
    <!---->
    <li _ngcontent-nve-c1=""><span _ngcontent-nve-c1="">11</span> : Mr. Nice</li>
    <!---->
    <li _ngcontent-nve-c1=""><span _ngcontent-nve-c1="">12</span> : Narco</li>
    <!---->
    <li _ngcontent-nve-c1=""><span _ngcontent-nve-c1="">13</span> : Bombasto</li>
    <!---->
    <li _ngcontent-nve-c1=""><span _ngcontent-nve-c1="">14</span> : Celeritas</li>
    <!---->
    <li _ngcontent-nve-c1=""><span _ngcontent-nve-c1="">15</span> : Magneta</li>
    <!---->
    <li _ngcontent-nve-c1=""><span _ngcontent-nve-c1="">16</span> : RubberMan</li>
    <!---->
    <li _ngcontent-nve-c1=""><span _ngcontent-nve-c1="">17</span> : Dynama</li>
    <!---->
    <li _ngcontent-nve-c1=""><span _ngcontent-nve-c1="">18</span> : Dr IQ</li>
    <!---->
    <li _ngcontent-nve-c1=""><span _ngcontent-nve-c1="">19</span> : Magma</li>
    <!---->
    <li _ngcontent-nve-c1=""><span _ngcontent-nve-c1="">20</span> : Tornado</li>
</ul>

参考 : Angularの便利タグng-container, ng-content, ng-template - Qiita

No.1789
06/15 17:25

edit

Angular router のページ遷移のイベント

● Angular router のページ遷移のイベント

https://angular.io/api/router/Event

NavigationStart,
RouteConfigLoadStart,
RouteConfigLoadEnd,
RoutesRecognized,
GuardsCheckStart,
ChildActivationStart,
ActivationStart,
GuardsCheckEnd,
ResolveStart,
ResolveEnd,
ActivationEnd
ChildActivationEnd
NavigationEnd,
NavigationCancel,
NavigationError
Scroll

解説

種別 発火タイミング
NavigationStart ナビゲーションが開始された時。
ActivationStart ナビゲーション先のコンポーネントが決まった時(GuardやResolveの前)。
ActivationEnd ナビゲーション先のインスタンスが作られた後)。
NavigationEnd ナビゲーションが終了した時(正常に終了した場合)。
NavigationCancel ナビゲーションが終了した時(ナビゲーション処理の途中でキャンセルされた場合)。
NavigationError ナビゲーションが終了した時(ナビゲーション先が存在しないなど、エラーが発生した場合)。

引用: https://bit.ly/37t3uU2

記述方法 イベント(NavigationStart)で操作を行う例」

  constructor( private _router: Router ) {

    _router.events.subscribe(event => {
      if(event instanceof NavigationStart) {
        // ここにページ遷移ごとに実行するメソッド
      }
    });

  }
No.1788
06/15 14:39

edit

Angular Fullcalendar を使用する

● Angular Fullcalendar を使用する

● パッケージのインストール

npm install --save @fullcalendar/angular @fullcalendar/core @fullcalendar/daygrid @fullcalendar/interaction @fullcalendar/timegrid

styles.scss

// add this
@import '~@fullcalendar/core/main.css';
@import '~@fullcalendar/daygrid/main.css';
@import '~@fullcalendar/timegrid/main.css';

app/app.module.ts

// add
import { FullCalendarModule } from '@fullcalendar/angular';

......

  imports: [
    BrowserModule,
    FullCalendarModule // add
  ],

app/app.component.ts

// calendar
import { FullCalendarComponent } from '@fullcalendar/angular';
import { EventInput } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGrigPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction'; // for dateClick
export class AppComponent {

  @ViewChild('calendar') calendarComponent: FullCalendarComponent; // the #calendar in the template

  calendarVisible = true;
  calendarPlugins = [dayGridPlugin, timeGrigPlugin, interactionPlugin];
  calendarWeekends = true;
  calendarEvents: EventInput[] = [
    { title: 'Event Now', start: new Date() }
  ];

  toggleVisible() {
    this.calendarVisible = !this.calendarVisible;
  }

  toggleWeekends() {
    this.calendarWeekends = !this.calendarWeekends;
  }

  gotoPast() {
    let calendarApi = this.calendarComponent.getApi();
    calendarApi.gotoDate('2000-01-01'); // call a method on the Calendar object
  }

  handleDateClick(arg) {
    if (confirm('Would you like to add an event to ' + arg.dateStr + ' ?')) {
      this.calendarEvents = this.calendarEvents.concat({ // add new event data. must create new array
        title: 'New Event',
        start: arg.date,
        allDay: arg.allDay
      })
    }
  }

}

No.1763
05/25 16:29

edit

Angular アプリを(サブディレクトリ)(プロジェクトを指定して)にビルド(デプロイ)する

● Angular アプリをサブディレクトリにビルド(デプロイ)する

・通常ビルドする

ng build

・ サブディレクトリ /angular/ にビルドする

ng build --base-href=/angular/

(最後のスラッシュは忘れずに!)

・ プロジェクトを指定してビルドする

ng build <プロジェクト名>

<プロジェクト名> には angular.json の

{
  "projects": {
    "my-app": {
    }
  }
}

で指定した my-app などの文字列を指定します。

なおプロジェクトは --projectで指定してもOK

$ npx ng build filter-keyup-events

ng help

ng help で build に関する記述を見てみます。

Compiles an Angular app into an output directory named dist/ at the given output path. Must be executed from within a workspace directory.
No.1761
08/06 16:47

edit

No.1715
03/04 22:05

edit

Angular で datetimepicker を使用する

● Angular で datetimepicker を使用する

またバリデーションにも対応させます。


* jquery , jquery-datetimepicker をインストール

npm install jquery --save
npm install jquery-datetimepicker  --save

* angular.json に 追加

            "styles": [
              "src/styles.scss" ,
              "node_modules/jquery-datetimepicker/build/jquery.datetimepicker.min.css"
            ],
            "scripts": [
              "node_modules/jquery/dist/jquery.min.js" ,
              "node_modules/jquery-datetimepicker/build/jquery.datetimepicker.full.min.js"
            ]


* app/app.component.ts に追加

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

// jquery
declare var $: any;


* 表示するページ page01 を新規作成

ng g component page01

1.(ルーティング) * app/app-routing.module.ts にルーティングを追加

const routes: Routes = [
  { path: 'page01', component: Page01Component }, 
  { path: '**', component: Page01Component }, // 追加
];

2.(html) app/page01/page01.component.html を以下の内容で保存

<input type="text" class="form-control jquery-datetimepicker" name="test-date" formControlName="datepicker" autocomplete="off">
<pre class="debug">
{{ registerForm.value | json }} <br>
Validation: {{ registerForm.get( 'datepicker' ).valid }}
</pre>

3.(TypeScript) app/page01/page01.component.ts を以下の内容で保存

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

// jquery
declare var $: any;

@Component({
  selector: 'app-page01',
  templateUrl: './page01.component.html',
  styleUrls: ['./page01.component.scss']
})
export class Page01Component implements OnInit {
  constructor() { }
  ngOnInit() {

    // ===== jquery-datetimepicker =====
    let _this = this;
    $.datetimepicker.setLocale('ja'); // 日本語化
    $('input.jquery-datetimepicker').datetimepicker({
      lang: 'ja',
      timepicker: false,
      format:'Y-m-d',
      onSelectDate:function( date ){
        var year = date.getFullYear();
        var  month = ("0"+(date.getMonth() + 1)).slice(-2);
        var  date =  ("0"+date.getDate()).slice(-2);
        var date_formatted = year + '-' + month + '-' + date;
        _this.registerForm.get('datepicker').setValue( date_formatted );
      }
    });
    // ===== jquery-datetimepicker =====

  }
}

これでコンポーネントは完成です。

jquery-datetimepicker で日付を選択時に、_this.registerForm.get('datepicker') にも値が反映されます。

No.1708
02/21 15:36

edit

Angular コーディングスタイルガイドの日本語訳抜粋

● Angular コーディングスタイルガイドの日本語訳抜粋

https://www.miraclelinux.com/tech-blog/4cd30h

おすすめです。

オブジェクト 記法
インターフェース名 パスカルケース(アッパーキャメル) interface Result {}
クラス名 パスカルケース(アッパーキャメル) export class ExceptionService
メソッド名 キャメルケース getName()
プロパティ名 キャメルケース private toastCount: number;
No.1707
06/15 09:33

edit

Laravel6 に jwt-auth をインストールしAngular の SPAからログインする(フロントエンド Angular編)

● Angularアプリの作成

ng new jwtauth-app
cd jwtauth-app
ng serve --open

● 必要なコンポーネント、サービスの作成

ng g component login
ng g component home
ng g service services/authentication

● 必要なガードの作成

ng g guard guard/auth

( CanActivate を選択して作成する )

app/guard/auth.guard.ts

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthenticationService } from '../services/authentication.service';

@Injectable()
export class AuthGuard implements CanActivate {
	constructor(
		private authService: AuthenticationService,
		private router: Router
	) { }

	canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
		if ( !this.authService.isAuthenticated() ) {
			this.router.navigate(['login']);
			return false;
		}
		return true;
	}
}

作成したガードを app/app.module.ts へ読み込ませる
( import して @NgModuleのprovidersに追加する )

app/app.module.ts

// guard
import { AuthGuard } from './guard/auth.guard';

@NgModule({
    ........
	providers: [AuthGuard],
})

● 必要なモデルの作成

mkdir src/app/models
vi src/app/models/user.ts

user.ts

export class User {
    id: number;
    username: string;
    password: string;
    firstName: string;
    lastName: string;
    token?: string;
}
app/home/<いくつかのファイル>
app/login/<いくつかのファイル>
app/services/<いくつかのファイル>

が作成されます

● bootstrap4 を Angularアプリにインストール

npm install --save bootstrap jquery popper.js

angular.json に以下を追加

    "styles": [
      "src/styles.scss" ,
      "node_modules/bootstrap/dist/css/bootstrap.min.css"
    ],
    "scripts": [
      "node_modules/jquery/dist/jquery.slim.min.js",
      "node_modules/popper.js/dist/umd/popper.min.js",
      "node_modules/bootstrap/dist/js/bootstrap.min.js"
    ]

● auth0/angular-jwt のインストール

npm install @auth0/angular-jwt

● ReactiveFormsModule の読み込み

app/app.module.ts

import { ReactiveFormsModule } from '@angular/forms';

  imports: [
    ReactiveFormsModule ,    // 追加
  ],
No.1704
02/17 16:46

edit

「ERROR in node_modules/rxjs/internal/types.d.ts(81,44): error TS1005: ';' expected.」エラーの対処法

● 「ERROR in node_modules/rxjs/internal/types.d.ts(81,44): error TS1005: ';' expected.」エラーの対処法

rxjs": "^6.0.0",

 ↓

rxjs": "6.0.0",
No.1706
02/17 10:44

edit

No.1701
02/13 15:38

edit

angular/router ルーターのルート一覧を表示させる

● Augury を使用する

https://chrome.google.com/webstore/detail/augury/elgalmkoelokbchhkhacckoklkejnhcd?hl=ja

● 手動でルート一覧を表示させる

http://bit.ly/2UKeBDD

import { Router, Route } from "@angular/router";

constructor(private router: Router) { }

ngOnInit() {
  this.printpath('', this.router.config);
}

printpath(parent: String, config: Route[]) {
  for (let i = 0; i < config.length; i++) {
    const route = config[i];
    console.log(parent + '/' + route.path);
    if (route.children) {
      const currentPath = route.path ? parent + '/' + route.path : parent;
      this.printpath(currentPath, route.children);
    }
  }
}
No.1699
02/13 14:26

edit

Angular do not found

Finally, I am able to solve that issue.
do() is replaced by tap().
for reference https://www.academind.com/learn/javascript/rxjs-6-what-changed/
and tap() should be inside .pipe().
like this, .pipe(tap())
for more reference, you can refer this link,
https://alligator.io/angular/angular-6/
and
https://www.learnrxjs.io/operators/utility/do.html

http://bit.ly/31LeglK

import { of } from 'rxjs';
import { tap, map } from 'rxjs/operators';
No.1698
02/12 16:01

edit

ionic で 横スクロールするナビゲーション

● ionic で 横スクロールするナビゲーション

<ion-content overflow-scroll="true">
......
</ion-content>

http://bit.ly/2H6NKK1
http://bit.ly/2H5gB1h

No.1695
02/08 22:37

edit

angular/router で 前のページURLを取得する

import { Router, NavigationEnd } from '@angular/router';
	constructor(
		private router: Router
	) {
		// 前のページURLを取得する
		this.currentUrl = this.router.url;
		router.events.subscribe(event => {
			if (event instanceof NavigationEnd) {
				this.previousUrl = this.currentUrl;
				this.currentUrl = event.url;
			}
		});
	}

これで this.previousUrl に前ページURLが入ります。

引用: http://bit.ly/31DcnHM

No.1694
02/08 20:54

edit

Ionic で Firebase ( Cloud Firestore ) を使用する

● angularfire2 のインストール

npm install angularfire2 firebase

● FirebaseのWEBコンソール画面からアプリを登録して設定情報をコピーしておく

var config = {
  apiKey: 'Your credentials here',
  authDomain: 'Your credentials here',
  databaseURL: 'Your credentials here',
  projectId: 'Your credentials here',
  storageBucket: 'Your credentials here',
  messagingSenderId: 'Your credentials here'
};

● モデル(インターフェース)の定義

app/models/song.interface.ts

export interface Song {
    id: string;
    albumName: string;
    artistName: string;
    songDescription: string;
    sonName: string;
}

● モデル(サービス)の定義

Cloud Firestore のコレクション songList を操作するサービスを記述します。

ionic generate service services/data/firestore

自動生成された app/services/data/firestore.service.ts に以下を追記

import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Song } from '../../models/song.interface';
export class FirestoreService {
	constructor(public firestore: AngularFirestore) { }
	createSong(
		albumName: string,
		artistName: string,
		songDescription: string,
		songName: string
	): Promise<void> {
		const id = this.firestore.createId();
		return this.firestore.doc(`songList/${id}`).set({
			id,
			albumName,
			artistName,
			songDescription,
			songName,
		});
	}
	getSongList(): AngularFirestoreCollection<Song> {
		return this.firestore.collection(`songList`);
	}
	getSongDetail(songId: string): AngularFirestoreDocument<Song> {
		return this.firestore.collection('songList').doc(songId);
	}
	deleteSong(songId: string): Promise<void> {
		return this.firestore.doc(`songList/${songId}`).delete();
	}
}

● /home 画面にデータ一覧を表示

app/home/home.page.ts に下記を追加

import { FirestoreService } from '../services/data/firestore.service';
import { Router } from '@angular/router';
export class HomePage {
	public songList;  // add this
	constructor(
		private firestoreService: FirestoreService,
		private router: Router
	) { }
	ngOnInit() {
		this.songList = this.firestoreService.getSongList().valueChanges();  // add this
	}
}

app/home/home.page.html に下記を追加

<ion-content class="ion-padding">
	<ion-card *ngFor="let song of songList | async" routerLink="/detail/{{song.id}}">
		<ion-card-header>
			{{ song.songName }}
		</ion-card-header>
		<ion-card-content>
			Artist Name: {{ song.artistName }}
		</ion-card-content>
	</ion-card>
</ion-content>

● ルール設定(セキュリティ設定)を行う

セキュリティ設定をしていない場合は、全てのアクセスが却下となります。 また一番ゆるく(全てを許可)すると、誰でもアクセスできるようになります。

*1. 誰でもアクセスできる設定

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}

この設定

export var firebaseConfig = {
    projectId: "my-project-name",
    storageBucket: "my-project-name.appspot.com",
};

だけで、誰でもアクセスできてしまいます。

*2. コレクション「songList」内なら誰でもアクセスできる設定

service cloud.firestore {
  match /databases/{database}/documents {
    match /songList/{songId} {
      allow read, write: if true;
    }
  }
}
なお {songId} は ワイルドカードです。
* と記述したいところですが、{songId}と書きます。
{songListId}でもいいみたいです。(文字列はなんでも良いらしい)

引用: http://bit.ly/2Om37Cz
http://bit.ly/385JJBi

● firestore について読むべき有益な情報

【図で解説】Firestoreでできること・できないこと
[Firebase][Cloud firestore] データをユーザーごとに所持するルール | deecode blog

No.1687
10/18 17:19

edit

Angular CLI からアプリの作成

● Angular CLI のインストール

npm install -g @angular/cli

● Angular CLI からアプリの作成

ng new myapp

● Angular CLI バージョンの確認

ng --version

● アプリの実行

ng serve --open
No.1683
08/06 10:46

edit

ionic で フォームバリデーションを作成する

● フォーム画面 /form/ に フォームバリデーションを作成する

* 1. app/form/form.page.ts へ記述

(モジュールの読み込み)
app/form/form.page.ts

// add
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';

(エラーメッセージの定義)
app/form/form.page.ts

	validations = {
		'username': [
			{ type: 'required', message: 'お名前は入力必須です' },
		],
		'email': [
			{ type: 'required', message: 'メールアドレスは入力必須です' },
		],
		'content': [
			{ type: 'required', message: 'お問い合わせ内容は入力必須です' },
		],
	};

(バリデーションフォームの定義)
app/form/form.page.ts

	public loginForm: FormGroup;

	constructor(
		public router: Router, 
		public formBuilder: FormBuilder) {

		this.loginForm = new FormGroup({
			username: new FormControl('', Validators.compose([
				Validators.required
			])),
			email: new FormControl('', Validators.compose([
				Validators.required
			])),
			content: new FormControl('', Validators.compose([
				Validators.required
			])),
		});
	}

* 2. app/form/form.page.html へ記述

(お名前フォームのみ)複数入力フォームがある場合は適宜追加すること

<form [formGroup]="loginForm">
    <ion-item>
        <ion-label position="stacked">お名前 <ion-text color="danger">*</ion-text></ion-label>
        <ion-input type="text" formControlName="username"></ion-input>

        <!-- error message -->
        <div class="error-container">
            <ng-container *ngFor="let validation of validations.username">
                <div class="error-message"
                    *ngIf="loginForm.get('username').hasError(validation.type) && (loginForm.get('username').dirty || loginForm.get('username').touched)">
                    <ion-icon name="information-circle-outline" color="danger"></ion-icon>
                    <ion-text color="danger">{{ validation.message }}</ion-text>
                </div>
            </ng-container>
        </div>
        <!-- /error message -->

    </ion-item>

	<div class="ion-padding">
		<ion-button [disabled]="!loginForm.valid" (click)="onClickSubmit()" expand="block" type="submit"
			class="ion-no-margin">送信する</ion-button>
	</div>

</form>

参考 : http://bit.ly/2RkXiXS

No.1680
01/24 19:17

edit

ionic で 次のページへリンクする / 遷移したページに戻るボタンをつける

https://localhost/posts/https://localhost/posts-show/123 への画面遷移を考えてみます。

* 1. posts-show ページの作成

ionic generate page posts-show

* 2. ルーティング posts-show/123 を受けれるようにする

app/posts-show/posts-show-routing.module.ts

const routes: Routes = [
  {
    path: ':postId',  // ● 引数を受ける変数を追加
    component: PostsShowPage
  }
];

* 3. posts.page.html からリンクを貼る。 app/posts/posts.page.ts に登録する。

app/posts/posts.page.html

	<ion-button expand="block" routerLink="/posts-show/" routerDirection="forward">詳細ページ1</ion-button>

* 4. posts-show ページに戻るボタンをつける

app/posts-show/posts-show.page.html

<ion-header>
	<ion-toolbar>
		// ● 追加 ↓
		<ion-buttons slot="start">
		    	<ion-back-button defaultHref="/posts"></ion-back-button>
		</ion-buttons>
		// ● 追加 ↑
		<ion-title>posts-show</ion-title>
	</ion-toolbar>
</ion-header>

デフォルトのリンク先(/posts)をつけておきます。
https://ionicframework.com/jp/docs/api/back-button

No.1679
01/24 13:29

edit

ionic の 表示イベント(ライフサイクル)

● Ionicの Page Life Cycle

https://ionicframework.com/jp/docs/angular/lifecycle

* 1. AngularのLife Cycle Events

Event Name Description
ngOnInit コンポーネントの初期化中に発生します。このイベントを使用して、ローカルメンバーを初期化し、一度だけ実行する必要があるServiceを呼び出すことができます。
ngOnDestroy Angularがビューを破棄する直前に発生します。 observables の unsubscribe などのクリーンアップに役立ちます。

* 2. IonicのPage Events

Event Name Description
ionViewWillEnter コンポーネントが表示されるアニメーションがはじまる時に発火します。
ionViewDidEnter コンポーネントが表示されるアニメーションが終了した時に発火します。
ionViewWillLeave コンポーネントを離脱するアニメーションがはじまる時に発火します。
ionViewDidLeave コンポーネントを離脱するアニメーションが終了した時に発火します。
No.1677
01/23 18:31

edit

ionic で now loading のインジケーターを表示させる

● ion-loading

https://ionicframework.com/jp/docs/api/loading

app/posts/posts.page.ts

import { LoadingController } from '@ionic/angular';

constructor に 以下のloadingController を追加

	constructor(
		private http: HttpClient, 
		public loadingController: LoadingController  // この行を追加
	) { }

以下を追加


	async ionViewDidEnter(){
		// define loading
		const loading = await this.loadingController.create({
			spinner: 'circular',
			message: 'loading ...',
			translucent: true,
		});
		// loading 表示
		await loading.present();

		// Make the HTTP request:
		this.http.get('https://YOUR-SERVER.TLD/api/posts').subscribe(data => {
			console.log(data);
			loading.dismiss();  // これを追加(jsonデータ完了時に loading を非表示とする)
		});
	}

No.1676
01/23 18:32

edit

No.1674
01/22 17:30

edit

ionic の 問い合わせフォームを作成する

● まずは一番シンプルなフォームを作成する

app/form/form.page.html

	<form #form="ngForm" (ngSubmit)="postForm(form.value)">
		<ion-item>
			<ion-label position="stacked">お名前 <ion-text color="danger">*</ion-text></ion-label>
			<ion-input type="text" [(ngModel)]="contact.username" name="contact.username"></ion-input>
		</ion-item>

		<ion-item>
			<ion-label position="stacked">メールアドレス <ion-text color="danger">*</ion-text></ion-label>
			<ion-input required email type="email" [(ngModel)]="contact.email" name="contact.email"></ion-input>
		</ion-item>

		<ion-item>
			<ion-label position="stacked">お問い合わせ内容 <ion-text color="danger">*</ion-text></ion-label>
			<ion-textarea [(ngModel)]="contact.content" name="contact.content"></ion-textarea>
		</ion-item>

		<div class="ion-padding">
			<ion-button expand="block" type="submit" class="ion-no-margin">送信する</ion-button>
		</div>
	</form>

app/form/form.page.ts

export class FormPage implements OnInit {

	// フォームパラメーターモデルの定義
	contact = {
		username: '' ,
		email: '' ,
		content: '',
	};

	constructor() {}
	ngOnInit() {}

	postForm(formValue){
		console.log('postForm()');
		console.log( formValue );
	}

}
No.1673
01/22 17:01

edit

ionic の html で for ループで回す

● ionic の html で for ループで回す

* .ts ファイルで プロパティを宣言

app/posts/posts.page.ts

export class PostsPage implements OnInit {
	posts_loop : {};

	ngOnInit(): void {
                posts_loop = {};
        }

* .html ファイルで ループを回す

app/posts/posts.page.html

	<ion-item *ngFor="let v of posts_loop;">
			<img src="{{v.file_url_array['0']}}" />
	</ion-item>
No.1670
01/21 21:33

edit

ionic の HttpClientModule で サーバの json を読み込む

● 1. モジュール HttpClientModule の登録

app/app.module.ts

// ● Add this
import { HttpClientModule } from '@angular/common/http';

  imports: [
    BrowserModule,
    HttpClientModule, // ● Add this
    ..... ,
    ..... ,

● 2. 各ページで使用する

例 (app/posts/posts.page.ts)

app/posts/posts.page.ts


// ● Add this
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';

....
....
        // ● Add this
	constructor(private http: HttpClient) { }

        // ● Add this
	ngOnInit(): void {
		// Make the HTTP request:
		this.http.get('https://YOUR-SERVER.TLD/api/posts').subscribe(data => {
			console.log(data);
			console.log(data[1]['name']);
		});
	}

No.1668
01/21 21:33

edit

ionic で画面を追加する

● ionic generate

ionic generate <type> <name> [options]

コマンド例

ionic generate
ionic generate page
ionic generate page contact
ionic generate component contact/form
ionic generate component login-form --change-detection=OnPush
ionic generate directive ripple --skip-import
ionic generate service api/user

実際の例

(posts ページを追加してみます。)(フォルダも作成できます。その場合は posts/index のように記述します。)

ionic generate page posts

こちらのファイルが追加されます

CREATE src/app/posts/posts-routing.module.ts (343 bytes)
CREATE src/app/posts/posts.module.ts (465 bytes)
CREATE src/app/posts/posts.page.scss (0 bytes)
CREATE src/app/posts/posts.page.html (124 bytes)
CREATE src/app/posts/posts.page.spec.ts (640 bytes)
CREATE src/app/posts/posts.page.ts (252 bytes)
UPDATE src/app/app-routing.module.ts (712 bytes)

1. サイドメニューにページを追加する

app/app.component.ts

  public appPages = [
    {
      title: 'Home',
      url: '/home',
      icon: 'home'
    },
    {
      title: 'List',
      url: '/list',
      icon: 'list'
    },
// 追加
    {
      title: 'Posts',
      url: '/posts',
      icon: 'clipboard'
    },
// 追加
  ];

icon はこちらから調べます
https://ionicons.com/

これで、サイドメニューに追加されて画面遷移が確認できます。

追加されたページに sidemenu を追加する

app/posts/posts.page.html

<ion-header>
	<ion-toolbar>
		<ion-title>posts</ion-title>
	</ion-toolbar>
</ion-header>

<ion-header>
	<ion-toolbar>
		<ion-buttons slot="start">
			<ion-menu-button></ion-menu-button>
		</ion-buttons>
		<ion-title>
			posts
		</ion-title>
	</ion-toolbar>
</ion-header>
No.1665
01/23 09:57

edit

No.1664
01/21 14:39

edit

ionicのはじめ方

● ionic の インストール

npm i -g ionic cordova

● ionic アプリの新規作成

Angular 4+ w/ Angular CLI

ionic start myapp

または
Angular 2/3 w/ @ionic/app-scripts

ionic start myapp --type=ionic-angular

ionic-angular のところは プロジェクトのタイプ を選択します。

Project Type Description
angular Ionic Angular 4+ w/ Angular CLI for Tooling
ionic-angular Ionic Angular 2/3 w/ @ionic/app-scripts for Tooling
ionic1 Ionic 1 w/ AngularJS

テンプレートの選択

 Starter template: (Use arrow keys)
❯ tabs     | A starting project with a simple tabbed interface 
  sidemenu | A starting project with a side menu with navigation in the content area 
  blank    | A blank starter project 
  super    | A starting project complete with pre-built pages, providers and best practices for Ionic development. 
  tutorial | A tutorial based project that goes along with the Ionic documentation 
  aws      | AWS Mobile Hub Starter 

● ionic アプリの起動

cd myapp
ionic serve --devapp

● 実機(iPhone , Android , iPad)で確認

ionic devapp をインストールします
https://ionicframework.com/docs/appflow/devapp

● チュートリアル

https://ionicframework.com/jp/docs/angular/your-first-app

● ionicをビルドしてWEBサーバへデプロイする

ionic build

www フォルダをアップロードすれば普通に動きます。

● ionic のバージョン確認

ionic info

--type=ionic-angular で作成したアプリの場合

Ionic:
   Ionic CLI          : 5.4.13 (/Users/xxxxx/.anyenv/envs/nodenv/versions/12.14.0/lib/node_modules/ionic)
   Ionic Framework    : ionic-angular 3.9.9
   @ionic/app-scripts : 3.2.4

Utility:
   cordova-res : 0.8.1
   native-run  : not installed

System:
   NodeJS : v12.14.0 (/Users/xxxxx/.anyenv/envs/nodenv/versions/12.14.0/bin/node)
   npm    : 6.13.4
   OS     : macOS Catalina

ionic4アプリの場合

Ionic:
   Ionic CLI                     : 5.4.13 (/Users/xxxxx/.anyenv/envs/nodenv/versions/12.14.0/lib/node_modules/ionic)
   Ionic Framework               : @ionic/angular 4.11.7
   @angular-devkit/build-angular : 0.801.3
   @angular-devkit/schematics    : 8.1.3
   @angular/cli                  : 8.1.3
   @ionic/angular-toolkit        : 2.1.1

Cordova:
   Cordova CLI       : 9.0.0 (cordova-lib@9.0.1)
   Cordova Platforms : not available
   Cordova Plugins   : not available

Utility:
   cordova-res : 0.8.1
   native-run  : not installed

System:
   NodeJS : v12.14.0 (/Users/xxxxx/.anyenv/envs/nodenv/versions/12.14.0/bin/node)
   npm    : 6.13.4
   OS     : macOS Catalina
No.1650
10/14 16:41

edit