MutationObserver

既存のカート機能がついたECサイトを立ち上げる際、既存のカート表示以外に、独自のカート表示を追加する必要がありました。

Ajaxで更新される既存のカート表示はそのままで別のカートにも同じ内容を反映するのですが、カート機能はこちらの独自カートの面倒は見てくれません。

そして初めてJavaScriptのオブザーバーAPIを使うことにしました。

コーディング

参考にしたのはMozilla Developer Networkのサイト(以下MDN)です。

MDNの解説にあるとおり、Nodeの変更を監視して処理を実行することができます。
監視対象は設定することができます。
※括弧内は設定するプロパティ名
・対象ノードの子ノード(childList)
・対象ノードの属性に対する変更(attributes)
・対象ノードのデータ(characterData)

今回はspanタグの中身でしたので、設定するプロパティ名から類推して「characterData」を監視対象に設定しました。
間違いだったわけですけど。

実際のソースを単純化したのが以下のものです。

<meta charset="UTF-8">
<title>TITLE</title>
<script src="./jquery-3.1.1.min.js"></script>
<script>
$(function(){
	$("#increment").on("click", function(){
		var count = parseInt($("#count").text());
		$("#count").text(++count)
	});
	
	// 対象とするノードを取得
	const target = document.getElementById('count');

	// オブザーバインスタンスを作成
	const observer = new MutationObserver((mutations) => {
	  mutations.forEach((mutation) => {
	    console.log(mutation.type);
	  });    
	});

	// オブザーバの設定
	const config = { characterData: true };
	 
	// 対象ノードとオブザーバの設定を渡す
	observer.observe(target, config);
	 
	// 後ほど、監視を中止
	observer.disconnect();
});
</script>
<span id="count">0</span><br>
<span id="result"></span><br>
<button id="increment">ADD</button>

※オブザーバーのコードはMDNの例を流用していますので、jQueryとピュアJavaScriptの記述が混在しています。

observerがcountを監視していますので、ADDボタンを押したらcountのテキストが加算されると同時に、observerのコールバックが実行され、発生したモーションの種類がデベロッパーコンソールに出力されるはずです。
監視対象は「characterData」ですので、コンソールにも「characterData」と出力される予定になっております。

さて。
ADDボタンを押します。
数字は加算されます。
しかし、コンソールには何も出力されません。
数字はどんどん加算できます。
しかし、いくら加算しようとコンソールは無言です。
寡黙すぎます。

どこがおかしいのか

observer.disconnect();

まず、ソースコード中の「observer.disconnect();」が怪しすぎます。
コメントにある「後ほど、監視を中止」の「後ほど」っていつなんでしょうか。
もしかして監視を開始したら即座に関しを停止しているんじゃないでしょうか。
この行をコメントします。

監視の種類

監視の種類にcharacterDataを選択しましたが、間違っている気がしてきました。
3種類全てを設定してみます。
MDNのサンプルコードからして、発生した監視の種類が全て出力されるはずです。
結果は「childList」・・・

MDNのページをよく読むと、childListの説明には「対象ノードの子ノード(テキストノードも含む)」とあります。
これが正解です。
よく読まないといけません。

で、最終的には(あんまり何も試行錯誤していないようですが、30分ぐらい悩む羽目に陥りました)以下のようなソースになりました。

<meta charset="UTF-8">
<title>TITLE</title>
<script src="./jquery-3.1.1.min.js"></script>
<script>
$(function(){
	$("#increment").on("click", function(){
		var count = parseInt($("#count").text());
		$("#count").text(++count)
	});
	
	// 対象とするノードを取得
	const target = document.getElementById('count');

	// オブザーバインスタンスを作成
	const observer = new MutationObserver((mutations) => {
	  mutations.forEach((mutation) => {
	    console.log(mutation.type);
	  });    
	});

	// オブザーバの設定
	const config = { childList: true };
	 
	// 対象ノードとオブザーバの設定を渡す
	observer.observe(target, config);
	 
	// 後ほど、監視を中止
	//observer.disconnect();
});
</script>

<span id="count">0</span><br>
<span id="result"></span><br>
<button id="increment">ADD</button>

しかし、consoleには2回出力されます。
コールバックが2回実行されているということです。

この謎はまだ解けていませんが今回の利用では問題ないので、当初の目的は達したということで。
そのうち調べるかもしれません。