LoginSignup
1
2

Materialize Tooltips のメッセージを動的に変更する

Posted at

1. はじめに

Web サーバから非同期で取得したメッセージを MaterializeTooltips で表示しようとしてハマったので、やり方をここに記載します。

2. 環境

Materialize 1.0.0
jQuery 3.7.1

3. やりたかったこと

特定の要素にマウスポインタが置かれた時に、Web サーバーからデータを取得し、それを Materialize のツールチップで表示しようとしました。
その際、ツールチップのメッセージを動的に変更する方法が分からず、手探りで動きを確認しながら実装を行いました。

4. デモ

「ここにマウスポインタを乗せてください」の上にマウスポインタを置くと、ローディングスピナーを載せたツールチップが表示され、2秒後にツールチップの表示内容が置き換わります。

index.html
<!DOCTYPE html>
<html lang="ja">
	<meta charset="UTF-8" />
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Materialize Tooltips - dynamic display demo</title>
	<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
	<script src="script.js"></script>
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
	<link rel="stylesheet" href="style.css">
<head>
</head>
<body>
	<div id="demo-container">
		<span
			class="btn tooltipped dynatp"
		 	data-tooltip="<div><div class='preloader-wrapper small active'><div class='spinner-layer spinner-blue-only'><div class='circle-clipper left'><div class='circle'></div></div><div class='gap-patch'><div class='circle'></div></div><div class='circle-clipper right'><div class='circle'></div></div></div></div></div>">
			ここにマウスポインタを乗せてください
		</span>
	</div>
</body>
</html>
script.js
$(() => {
    $('.tooltipped').tooltip();

	$(document).on('mouseover', '.dynatp', (event) => {
		const dis = $(event.target);

		// サーバーからAjaxでデータ取得(ここではタイマーで代用)
		setTimeout(() => {
			const tltp = $(dis.attr('data-tooltip'));
			tltp.empty();
			tltp.append('<div>[動的メッセージデモ]<br>これは動的に設定されたメッセージです。</div>');
			dis.attr('data-tooltip', tltp.prop('outerHTML'));

			// ツールチップ表示中判定
			const isOpen = dis[0].M_Tooltip && dis[0].M_Tooltip.isOpen;
			if (isOpen) {
				dis.tooltip('close');
			}

			// ツールチップの再構成
            dis.tooltip('destroy');
			dis.tooltip();

			if (isOpen) {
				dis.tooltip('open');
			}
		}, 2000);
	});
});
style.css
#demo-container {
	margin: 20px;
}

動きの確認は↓

See the Pen Materialize Tooltips - dynamic display demo by Koji Hataya (@hataya_koji) on CodePen.

5. 解説

index.html と script.js について解説します。
※style.css は説明を割愛します。

5.1 index.html

ここでの注目箇所は、ツールチップが適用される <span> 要素の data-tooltip 属性になります。
この属性には HTML 文字列をセットしていますが、内容はローディングスピナーの定義です。
これにより、表示対象データの取得が完了するまで、ツールチップにはローディングスピナーが表示されるようになります。
ちなみにローディングスピナーは、Materialize が提供しているものを使用しています。

data-tooltip 属性の設定値(※見やすいように改行とインデントを入れました)
<div>
    <div class='preloader-wrapper small active'>
        <div class='spinner-layer spinner-blue-only'>
            <div class='circle-clipper left'>
                <div class='circle'></div>
            </div>
            <div class='gap-patch'>
                <div class='circle'></div>
            </div>
            <div class='circle-clipper right'>
                <div class='circle'></div>
            </div>
        </div>
    </div>
</div>

5.2 script.js

$('.tooltipped').tooltip();

CSS クラス "tooltipped" を持つ要素に対し、ツールチップを適用しています。

$(document).on('mouseover', '.dynatp', (event) => {

CSS クラス "dynatp" を持つ要素のマウスオーバーイベントを拾って処理しています。
この要素は、上記のツールチップを適用された要素("tooltipped")と同じものになりますが、ツールチップ適用対象は "tooltipped"、動的メッセージ対象は "dynatp" と区別して使用しています(ツールチップ適用対象だが、動的メッセージ対象ではない要素があると困るので)。

const tltp = $(dis.attr('data-tooltip'));  // (1)
tltp.empty();  // (2)
tltp.append('<div>[動的メッセージデモ]<br>これは動的に設定されたメッセージです。</div>');  // (3)
dis.attr('data-tooltip', tltp.prop('outerHTML'));  // (4)

(1) data-tooltip 属性の設定値(HTML文字列)を jQuery オブジェクトに変換し、tltp 変数(定数)に代入しています。
(2) <div>~</div> の内側の定義(ローディングスピナー)を消去しています。
(3) <div>~</div> の内側に新規メッセージを追加しています。
(4) 書き換えた HTML 定義を対象要素の data-tooltip 属性に上書きしています。外側の <div> 要素も含めるため、~.prop('outerHTML') で HTML 文字列を出力しています。

// ツールチップ表示中判定
const isOpen = dis[0].M_Tooltip && dis[0].M_Tooltip.isOpen;
if (isOpen) {
    dis.tooltip('close');
}

// ツールチップの再構成
dis.tooltip('destroy');
dis.tooltip();

if (isOpen) {
    dis.tooltip('open');
}

実は data-tooltip 属性に新たな内容を書き戻しても、ツールチップに表示される内容は変わりません。
したがって、
dis.tooltip('destroy');
でツールチップを破棄して
dis.tooltip();
で作り直しています。
これが今回のキモです。

その他、ツールチップの表示中に内容が作り直されると、勝手にツールチップが閉じられたようになってしまうため、ツールチップが表示中かどうかの判定と再表示処理を入れています。

6. おわりに

今回のデモでは必要最小限のコードしか記載していないため、私が実際に使用してるコードには少し処理が加えられています。

たとえば、運用では Web サーバーから非同期で取得したデータをツールチップに表示していますが、データ取得後は同処理が実行されないようにガードしています。
また、動的メッセージ表示対象の要素が複数あり、各々取得するデータが異なるため、それを識別するキーを data-xxx 属性で持つようにしています。

いずれも簡単に実現できますので、興味のある方は試してみてください。

7. 参考にさせていただいた情報

Documentation - Materialize
https://materializecss.com/

1
2
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
1
2