中安拓也のブログ

プログラミングについて書くブログ

エラー「angular/compiler-cliが適切にインストールされてません」

遭遇したエラー

"@angular/compiler-cli" package was not properly installed. Error: Error: Cannot find module '@angular/compiler-cli'

npm installをした後に、ng serveコマンドでアプリを起動しようとした時に発生しました。

バージョン情報

  • angular/cli: 1.6.5

  • Angular: 5.2.3

  • Typescript: 2.4.2

  • OS: darwin x64

  • Node: 8.1.4

エラーの修正手順

node_modulesを削除した後に、再度npm installコマンドを実行することで解決できます。

Angular + Reduxを学ぶ #2 - Redux DevTools chrome extension を使う

引き続きangular-redux/storeの使い方について、前回記事はこちら

Redux DevTools chrome extensionを導入してブラウザデバックの効率を上げましょう。

バージョン情報

  • Angular: 5.2.3

  • angular-redux/store: 7.1.0

  • TypeScript: 2.5.3

  • angular/cli: 1.6.5

  • OS: darwin x64

  • Node: 8.1.4

手順

Redux DevTools chrome extensionをお使いのChromeに入れてください。

f:id:l08084:20180310183553p:plain

インストールした後は、Redux DevToolsでデバックしたいAngularアプリのapp.module.tsを編集します。

// <- addとコメントされている行を追加してください。

src/app/app.module.ts:

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

import { AppComponent } from './app.component';
import { NgRedux, NgReduxModule, DevToolsExtension } from '@angular-redux/store';
import { rootReducer } from '../state/reducer';
import { INITIAL_STATE, IAppState } from '../state/store';
import { FlappyBirdActions } from '../state/action';

import 'rxjs/Rx';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    NgReduxModule,
  ],
  providers: [
    FlappyBirdActions,
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
  constructor(
    ngRedux: NgRedux<IAppState>,
    devTools: DevToolsExtension) { // <- add
      const storeEnhancers = devTools.isEnabled() ? // <- add
      [ devTools.enhancer() ] : // <-add
      []; // <-add
      ngRedux.configureStore(
        rootReducer,
        INITIAL_STATE,
        [], // <- add
        storeEnhancers); // <- add
  }
}

これで準備は完了です。アプリを立ち上げて、Chrome DevTools(開発者ツール)のReduxタブを選択してください。

f:id:l08084:20180310184820p:plain

👆こんな感じでStateの最新状態の閲覧、アクションの巻き戻しや再生が可能になります。

参考サイト

store/intro-tutorial.md at master · angular-redux/store · GitHub

Angular CLI で作ったアプリから画像を参照する

Angularアプリによる画像フォルダの作成方法 & アクセスの仕方

バージョン情報

  • angular/cli: 1.6.5

  • Angular: 5.2.3

  • Typescript: 2.4.2

  • OS: darwin x64

  • Node: 8.1.4

画像フォルダを作ってファイルを置く

src/app/assetsimagesディレクトリを作成する

f:id:l08084:20180310165603p:plain

アクセスしたい画像ファイルを置く

f:id:l08084:20180310171602p:plain

CSSからアクセスする

src/app/app.component.scss:

.wall {
    background-image: url(/assets/images/white-wood.jpg);
}

HTMLからアクセスする

src/app/app.component.html:

<img #bird [ngStyle]="birdPosition$ | async"
 class="bird" src="/assets/images/bird.png">

参考サイト

webpack - Using Angular CLI and unable to use relative image paths in CSS files - Stack Overflow

Best place to put assets folder? · Issue #713 · angular/angular-cli · GitHub

TypeScriptで遭遇したエラー: プロパティ 'style' は型 'Element' に存在しません。

遭遇したエラーと対処法について

エラー内容

Type 'HTMLCollectionOf<Element>' is not an array type or a string type.
(プロパティ 'style' は型 'Element' に存在しません。)

エラーの出たコード

複数のDOM要素を取得した後に、ループを回してスタイルプロパティを取得、表示しようとした。

const wallList = document.getElementsByClassName('wall');
for (let i = 0; i < wallList.length; i++) {
  const left = wallList[i].style.left; // <- エラー発生!!
  console.log(left);
}

const left = wallList[i].style.left;の部分で表題のエラーが発生している。

エラー原因

document.getElementsByClassNameの戻り値の型はHTMLCollectionOf<Element>になるが、Elementにはstyleプロパティが存在しないためエラーになっている。

HTMLElementにキャストする

ElementからstyleプロパティのあるHTMLElementにキャストすると解決する。

const wallList = document.getElementsByClassName('wall') as HTMLCollectionOf<HTMLElement>;
for (let i = 0; i < wallList.length; i++) {
  const left = wallList[i].style.left;
  console.log(left);
}

as HTMLCollectionOf<HTMLElement>でキャストすることにより、エラーが消えた。

参考サイト

github.com

Angularで新規にDOMを作成して、コンポーネントに挿入する

AngularでDOMを操作したい時にRenderer2クラスを利用することができる。

バージョン情報

  • Angular: 5.0.3

  • node: 8.1.4

  • macOS High Sierra(10.13.3)

  • Ionic: 3.9.2

Renderer2クラスの使い方

実際のコードでRenderer2クラスの利用方法について説明していく。

サンプルコードで実現すること

アプリ起動から10秒後に、コンポーネント内で作成したdiv要素をDOMに挿入して、壁を出現させたい。

f:id:l08084:20180307201335p:plain

👆の画像はまだ壁が出現していない状態。

サンプルコード

src/pages/home/home.ts:

import { Component, ElementRef, AfterViewInit, Renderer2 } from '@angular/core';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage implements AfterViewInit {

  // Renderer2クラスをDIする
  constructor(private renderer2: Renderer2,
              private el: ElementRef) {}

  ngAfterViewInit() {
    // 10秒後に壁を表示する
    Observable.interval(10000)
      .subscribe(() => this.setWall())
      .unsubscribe();
  }

  setWall = (): void => {
    const pos = 40;

    // div要素を二つ作成
    const wallTop = this.renderer2.createElement('div');
    const wallBottom = this.renderer2.createElement('div');

    // div要素にスタイルクラスwallを追加
    this.renderer2.addClass(wallTop, 'wall');
    this.renderer2.addClass(wallBottom, 'wall');

    // div要素のスタイルを変更
    this.renderer2.setStyle(wallTop, 'bottom', `${pos + 10}%`);
    this.renderer2.setStyle(wallBottom, 'top', `${(100 - pos) + 10}%`);

    this.renderer2.setStyle(wallTop, 'left', `400px`);
    this.renderer2.setStyle(wallBottom, 'left', `400px`);

    // 自コンポーネントの配下に作成したdiv要素を挿入する
    this.renderer2.appendChild(this.el.nativeElement, wallTop);
    this.renderer2.appendChild(this.el.nativeElement, wallBottom);
  }
}

実行結果

10秒後にRenderer2クラスで作成したdiv要素(壁)が出現する

f:id:l08084:20180307203413p:plain

参考サイト

Angular

AngularのViewChildで取得した要素の幅や高さを表示する

HTML要素の幅や高さを%などで指定している場合、Angular側でサイズがわからなくて困る時がある

バージョン情報

  • Angular: 5.0.3

  • node: 8.1.4

  • macOS High Sierra(10.13.3)

  • Ionic: 3.9.2

サイズ取得方法

f:id:l08084:20180304201009p:plain

CSSのパーセント指定でサイズを設定した画像(鳥)の幅と高さを取得する

.bird {
    height: 30%;
    width: 30%;
}

ElementRef.nativeElementでDOMの情報を取得することができる。

import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';

@Component({
  selector: 'page-home',
  template: `<img #bird class="bird" src="assets/imgs/bird.png">`
})
export class HomePage implements AfterViewInit {

  @ViewChild('bird') bird: ElementRef;

  constructor(public navCtrl: NavController) {}
  
  ngAfterViewInit() {
    // ElementRef.nativeElementでDOMの情報を取得
    const height = this.bird.nativeElement.offsetHeight;
    const width = this.bird.nativeElement.offsetWidth;
    // ViewChildで取得した要素のサイズを表示する
    console.log(`height: ${height}`);
    console.log(`width: ${width}`);
  }
}

offsetWidthoffsetHeightはCSSの「padding」「border」を含んだ状態での幅、高さとなる。

実行結果

👆のコードを実行した結果、console.logで鳥の幅と高さが出力されていることがわかる。

f:id:l08084:20180304201147p:plain

参考サイト

blog.yuhiisk.com

alphasis.info

Ionicで画像の設定

画像を設定する前のアプリ画面 f:id:l08084:20180304163519p:plain

はじめに

Ionicで画像を設定する方法について

バージョン情報

  • Ionic: 3.9.2

  • Angular: 5.0.3

  • node: 8.1.4

  • macOS High Sierra

画像設定方法

設定したい画像(例では、isometropolis.jpg)をsrc/assets/imgs配下に置く。 f:id:l08084:20180304160647p:plain

CSS(SCSS)から画像を参照する場合

CSSからは、パスを../assets/imgs/[画像ファイル名称]に設定すると画像を参照できる。

src/pages/home/home.scss

page-home {
    background-image: url(../assets/imgs/isometropolis.jpg)
}

HTMLから画像を参照する場合

HTMLからは、パスをassets/imgs/[画像ファイル名称]に設定すると画像を参照できる。

src/pages/home/home.html:

<img id="bird" src="assets/imgs/bird.png">

画像を設定した後のアプリ画面

f:id:l08084:20180304162651p:plain

参考サイト

sndbox.jp