LoginSignup
9
9

More than 5 years have passed since last update.

AngularDart入門 第4回 既存のHTML要素を拡張する

Last updated at Posted at 2014-10-25

第3回ではコンポーネントについて解説しました。今回はデコレーターについて詳しく説明します

今回の元記事は4. Creating a Custom Decoratorです。

今回は次のようなツールチップ用の独自属性を定義します。

<span tooltip="tooltipForRecipe(recipe)">
  ...
</span>

まずはサンプルアプリを動かしてみよう

こちらにサンプルアプリのソースコードがあります。リポジトリをクローンして、Chapter_04ディレクトリで> pub serveすればサンプルアプリが起動します。

Imgur

第3回と同様にレシピ一覧とその詳細が表示されます。また、一覧のアイテムにマウスを乗せるとツールチップが表示されます。

デコレーターの作成

ツールチップ用のデコレーターの作成は次の手順で行います。

  • 2つのクラスの追加 : Tooltip(デコレーターの実装クラス)とTooltipModel(データを持つモデル)
  • RecipeBookComponentの変更 : レシピからツールチップのモデルを作成
  • web/main.dartでTooltipの登録
  • ツールチップのデコレーターを使う

デコレーターの定義

デコレーターは次のように定義します。

...
import 'package:angular/angular.dart';

@Decorator(selector: '[tooltip]')
class Tooltip {
  final dom.Element element;

  @NgOneWay('tooltip')
  TooltipModel displayModel;
  ...
  Tooltip(this.element) {
    ...
  }
  ...
}

前回も説明したとおり、selectorにはコンポーネントを表すCSSセレクタを指定します。上の例では[tooltip]はDOM属性として定義されています。また、tooltip属性(この場合自分自身)の値はdisplayModelに対してHTMLからDartへの一方通行のバインディングを定義しています。このデコレーターは次のように呼び出すことになります。

<span tooltip="tooltipForRecipe(recipe)">

デコレーターのコンストラクタは、そのデコレーターが適用されたDOM要素が表示された際に呼ばれ、コンストラクタの引数としてElement型のインスタンスが与えられます。

デコレーターによるDOMの操作

ツールチップの実装の中で最も重要なのは<div>要素を作成し、DOMに追加している部分です。マウスオーバーのイベントが発生するとコールバックでこの処理が実行されます。

import 'dart:html' as dom;
...
// In an onMouseEnter handler:
tooltipElem = new dom.DivElement();

// ...Create children using info from displayModel...
// ...Add the children to the <div>...
// ...Style the <div>...

dom.document.body.append(tooltipElem);

重要 デコレーターでDOMを操作する際は次のことに気をつけましょう

  • DOMの操作はコンストラクタ 以外で行う
  • Angularが管理している要素は破棄しない

AngularはDOMの全体を管理しているので、コードで直接DOMを操作する際は十分注意しましょう

ツールチップのデータモデルは次のようになっています

class TooltipModel {
  String imgUrl;
  String text;
  int imgWidth;

  TooltipModel(this.imgUrl, this.text, this.imgWidth);
}

ツールチップのモデルを生成する

recipe-bookコンポーネントでレシピのデータからツールチップのモデルを生成します。

class RecipeBookComponent {
  ...
  static final tooltip = new Expando<TooltipModel>();
  TooltipModel tooltipForRecipe(Recipe recipe) {
    if (tooltip[recipe] == null) {
      tooltip[recipe] = new TooltipModel(recipe.imgUrl,
          "I don't have a picture of these recipes, "
          "so here's one of my cat instead!",
          80);
    }
    return tooltip[recipe]; // recipe.tooltip
}

ここでExpandoを使っているのは実装上の工夫です。Expandoはすでに存在するオブジェクトに新たなプロパティを関連付ける方法の一つです(この場合はRecipeTooltipModelを関連付ける)。

コンポーネントとデコレーター

デコレーターは属性としてのコンポーネントと似ていますが、デコレーターにはスコープが無いという点が大きく違います。デコレーターは単にHTML要素に新しい機能を追加するだけの修飾でしかありません。

まとめ

  • デコレーターは既存のHTML要素を拡張する
  • デコレーターはスコープを持たない
  • DOMを直接操作する際は注意する

第5回5. Introducing Formatters and Services
を元にバージョン1.0に置き換えて解説します。

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9