質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
AngularJS

AngularJSはオープンソースのJavaScriptフレームワークです。ブラウザ上で動作するウェブアプリケーションの開発にMVCアーキテクチャを取り入れることを目的としています。

Q&A

1回答

3840閲覧

AngularJS 1.3 $watchが監視できるものは?

Takahashi-Ei

総合スコア60

AngularJS

AngularJSはオープンソースのJavaScriptフレームワークです。ブラウザ上で動作するウェブアプリケーションの開発にMVCアーキテクチャを取り入れることを目的としています。

1グッド

0クリップ

投稿2016/02/12 08:55

編集2016/02/12 09:09

はじめてお世話になります。

親コントローラを用いずに、$watchを使って、コントローラ間の値を受け渡す実験をしています。

html

1<!DOCTYPE html> 2<html lang="ja" ng-app="app"> 3<head> 4 <meta charset="utf-8" /> 5 <title>テスト</title> 6 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.20/angular.js"></script> 7 <script> 8 var app = angular.module('app', []); 9 app.value('myValue', ''); 10 app.controller('InputController', ['$scope', 'myValue', function($scope, myValue){ 11 $scope.onInputChange = function(){ 12 myValue = $scope.myInput; 13 } 14 }]); 15 app.controller('OutputController', ['$scope', 'myValue', function($scope, myValue){ 16 $scope.$watch(function(){ 17 return myValue; 18 }, function(){ 19 $scope.myOutput = myValue; 20 }); 21 }]); 22 </script> 23</head> 24<body> 25 <div ng-controller="InputController"> 26 <input ng-model="myInput" ng-change="onInputChange()" type="text" /> 27 </div> 28 <div ng-controller="OutputController"> 29 {{ myOutput }} 30 </div> 31</body> 32</html> 33

Module#value経由で、InputControllerのプロパティの値をOutputControllerのプロパティに受け渡したいのですが、上記のように、Module#valueの値が生の文字列では、$watchのリスナーが発火せず、うまくいきませんでした。

そこで、scriptタグ間を下記のように書き換えて、

javascript

1var app = angular.module('app', []); 2app.value('myValue', {value: ''}); 3app.controller('InputController', ['$scope', 'myValue', function($scope, myValue){ 4 $scope.onInputChange = function(){ 5 myValue.value = $scope.myInput; 6 } 7}]); 8app.controller('OutputController', ['$scope', 'myValue', function($scope, myValue){ 9 $scope.$watch(function(){ 10 return myValue.value; 11 }, function(){ 12 $scope.myOutput = myValue.value; 13 }); 14}]);

Module#valueの値をオブジェクトにして、そのメンバを媒介にしてやるとうまくいきました。

やってることは一緒だと思うのですが、一体なぜこのようなことが起こるのでしょうか?
$watchの最初の引数である無名関数を、逐一検査しているわけではないのですか?

よろしくお願いいたします。

miyabi-sun👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

(このコメントには、明確な回答は記載されておりません。。。 ごめんなさい)

下記箇所にて値を確認してみると、今回の問題の原因が見えてくるのではないでしょうか。

  1. $scope.onInputChange の myValue をセットした後の myValue値
  2. $scope.myOutput にセットした後の myValue 値

Javascript

1var app = angular.module('app', []); 2app.value('myValue', ''); // 値を設定した場合 3app.value('myObject', {value:""}); // オブジェクトを設定した場合 4app.controller('InputController', ['$scope', 'myValue', 'myObject', function($scope, myValue, myObject){ 5 $scope.onInputChange = function(){ 6 myValue = $scope.myInput; 7 myObject.value = $scope.myInput; 8 console.log("InputController:", myValue, myObject) 9 } 10}]); 11app.controller('OutputController', ['$scope', 'myValue', 'myObject', function($scope, myValue, myObject){ 12 13 // myValue が変更されたかどうかを監視する処理 14 $scope.$watch(function(){ 15 return myValue; 16 }, function(){ 17 // myValue, myHash の値を確認 18 console.log("OutputController 1:", myValue, myObject) 19 }); 20 21 // myHash が変更されたかどうかを監視する処理 22 $scope.$watch(function(){ 23 return myObject.value; 24 }, function(){ 25 // myValue, myHash の値を確認 26 console.log("OutputController 2:", myValue, myObject) 27 }); 28}]);

Javascript

1// "a" を入力 2"InputController:" "a" Object { value: "a" } test.html:15:16 3"OutputController 2:" "" Object { value: "a" } test.html:28:14 4// "a" を入力 (2回目) 5"InputController:" "aa" Object { value: "aa" } test.html:15:16 6"OutputController 2:" "" Object { value: "aa" } test.html:28:14 7// "a" を入力 (3回目) 8"InputController:" "aaa" Object { value: "aaa" } test.html:15:16 9"OutputController 2:" "" Object { value: "aaa" } test.html:

結果の通り、InputController: myValue は変更されているにもかかわらず、OutputController: myValue の値は変更されていないようですね。
→ InputController:myValue と OutputController:myValue は正しくシェアリングできておらず、別物となっているようです。

$watchの最初の引数である無名関数を、逐一検査しているわけではないのですか?

正確には、何らかの変更が発生した際、第一引数(の要素?)が変更されたかどうかを確認しているのです。


でわ、何故こんなこと(正しくシェアリングができていない)になったのかと聞かれると、非常に説明しにくいところなのです。。。

関数の呼び出し時に引数を渡した場合、「プリミティブ型は値渡し」「オブジェクト型は参照渡し」(Javascript)となるのはご存知でしょうか。
おそらくはこの辺りが原因ではないかと考えております。

投稿2016/02/15 02:35

usk

総合スコア397

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Takahashi-Ei

2016/02/15 05:01

ご回答ありがとうございます。 > 正確には、何らかの変更が発生した際、第一引数(の要素?)が変更されたかどうかを確認しているのです。 つまり、プリミティブ型は監視の対象にならないということでしょうか? > 関数の呼び出し時に引数を渡した場合、「プリミティブ型は値渡し」「オブジェクト型は参照渡し」(Javascript)となるのはご存知でしょうか。 おそらくはこの辺りが原因ではないかと考えております。 そうかもしれませんね。そう書いてあるソースがあればいいのですが…。
usk

2016/02/16 00:07

> つまり、プリミティブ型は監視の対象にならないということでしょうか? これもまた、混乱させる原因なのですが、、、同一コントローラー内での watch は正しく監視されます。 InputController 内で $scope.watch(myValue, function() {}) は正しく判断されます。 「正しく $watch 出来ない」というよりかは、「app.value で定義した変数が正しく共有化できていない」と考えたほうがよさそうです。 つまり、異なるコントローラー間でデータ共有する場合、質問者様のお題に合った通り、プリミティブ型ではなくオブジェクト型を利用したほうが安全ということです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問