8

AngularJS を理解するために、例の 1 つをいじってみることにしました。具体的には、ユーザーが 5 つの todo を入力すると、スイッチ ケースを使用して別の div に切り替える「完了」画面を Todo サンプルに追加するだけです。 . コードはhttp://jsfiddle.net/FWCHU/1/で入手できます。

ただし、各 switch-case は独自のスコープを取得するように見えますが ($scope.todoText は使用できません)、この場合は addTodo() 内から「this」を使用してアクセスできます。ここまでは順調ですが、switch-case の外部にある todoText (switch-case の内部) にアクセスしたい場合、どうすればよいでしょうか? switch-case スコープをモデルにバインドできますか? 他の方法でアクセスできますか、それとも他の方法で解決する必要がありますか?

PS。上記のコードの解決策を見つけようとしているわけではありません。スイッチケースを使用せずに解決する方法を知っていると確信しています。この場合、スコープがどのように機能するかを理解したいです!

4

2 に答える 2

8

マークはいくつかの素晴らしい提案をしています! AngularJS Batarang Chrome 拡張機能もチェックして、さまざまなスコープとその値を (とりわけ) 確認してください。jsFiddle ではうまく動作しないように見えることに注意してください。

内部スコープに直接アクセスする方法はわかりませんが、プリミティブではなくオブジェクトにバインドすることで、外部スコープの同じテキストにアクセスする 1 つの方法を次に示します。

todoText1)コントローラーでプリミティブではなくオブジェクトとして宣言します。

$scope.todoText = {text: ''};

todoText.text2)ただの代わりにバインドするtodoText:

<form ng-submit="addTodo()">
    <input type="text" ng-model="todoText.text" size="30" placeholder="add new todo here">
    <input class="btn-primary" type="submit" value="add">
</form>

3) 使用する既存の関数を変更しますtodoText.text

$scope.addTodo = function() {
    $scope.todos.push({text:$scope.todoText.text, done:false, width: Math.floor(Math.random() * 100) + 50});
    $scope.todoText.text = '';
};

このフィドルを見て、何かを入力したときにテキストボックスの下に表示されるテキストがtodoText.text外側のスコープにアクセスしていることに注意してください。

プリミティブを使用するようにコードを元に戻すと (この fiddleのように)、親スコープtodoTextはテキスト ボックスに加えた変更を反映しません。これは、JavaScript が参照値をコピーする方法 (詳細については、この投稿を参照) に関係している可能性が高く、AngularJS 固有のものではありません。

于 2012-09-13T21:42:16.887 に答える
5

Update2: AngularJS についてもう少し知ったので、ここにもっと良い答えがあります。

switch-case の外側にある todoText (switch-case の内側) にアクセスしたい場合、どうすればよいでしょうか?

親スコープが子スコープにアクセスする方法はありません。(この制限の理由の 1 つは、 Angular 開発者によると、スコープのメモリ管理を容易にするためです。) (まあ、$$childHead と $$childTail を使用して子スコープにアクセスできますが、そうしないでください!)

switch-case スコープをモデルにバインドできますか? 他の方法でアクセスできますか、それとも他の方法で解決する必要がありますか?

子スコープから親モデルにアクセスするには、次の 3 つの一般的な方法があります。

  1. @Gloopy が提案することを実行します。親スコープでオブジェクトを作成し、子スコープでそのオブジェクトのプロパティを参照します。
  2. 子スコープで $parent を使用して、親スコープとそのプロパティ (プリミティブ プロパティであっても) にアクセスします。
  3. 親スコープでメソッドを呼び出す

$parent を使用するようにフィドルを変換するには:

<input type="text" ng-model="$parent.todoText" ...

$scope.addTodo = function() {
   $scope.todos.push({text: $scope.todoText, ...
   $scope.todoText = '';

Gloopy の回答に関するコメントで述べたように、ng-repeat と ng-switch はどちらも、プロトタイプとして親スコープから継承する新しい子スコープを持っています。ng-repeat は、ループ変数/項目も新しい子スコープにコピーします (そして、@Gloopy がプリミティブとオブジェクトで説明するニュアンスが適用されます)。ng-switch は親スコープから何もコピーしません。

内部/子スコープがどのように見えるかを確認するには、ng-switch-when の後に次を追加します。

<a ng-click="showScope($event)">show scope</a>

これをコントローラーに追加します。

$scope.showScope = function(e) {
    console.log(angular.element(e.srcElement).scope());
}

Update1: (悪いアドバイスには取り消し線が追加され、わかりやすくするために [] が追加されました)

このシナリオでは、AngularJS が追加の内部スコープを (暗黙的に) 作成しており、実際には別のコントローラーを必要としない/必要としないため、Gloopy のソリューションが気に入っています。サービス (私が最初に以下で提案したもの) は [これを行う間違った方法]おそらくやり過ぎです。また、Gloopy のソリューションではコントローラー メソッドで「this」を使用する必要がないことも気に入っています。

元の回答: (悪いアドバイスには取り消し線を追加、わかりやすくするために [] を追加)

スコープが作成されている場所を確認するには (まだ試していない場合は便利です):

.ng-scope { margin: 4px; border: 1px dashed red }

switch-case の外側 (したがってそのスコープの外側) に todoText にアクセスするには、複数のスコープが関与するため、基本的にコントローラー間の通信について質問します。いくつかのオプションがありますが、おそらくサービスが最適です。(共有する必要がある) データをサービス内に格納し、データへのアクセスが必要な各コントローラーにそのサービスを挿入します。

あなたの特定の例では、共有データにアクセスするには、コントローラーを各スイッチケースに接続し、サービスを注入する必要があると思います。

AngularJS: コントローラー間で変数を渡すにはどうすればよいですか?も参照してください。.

その他のオプション:

内側のスコープで $scope.$parent を使用することは [これを行う 1 つの方法 -- 上記の Update2 を参照]はお勧めしません。これは、コントローラーがデータの表示方法について仮定を立てることになるためです。

単純な 1 回限りのアプリケーションを除いて、$rootScope の使用はお勧めしません。その共有データは独自の生活を始める可能性があり、$rootScope はそれが起こる場所ではありません。サービスは、再利用や動作の追加などが容易です。

$scope.$emit を使用することも別のオプションですが、(動作をトリガーする代わりに) データを共有するためにイベントを発行するという、面倒で少し奇妙に思えます。

[親スコープでオブジェクトを使用するのがおそらく最善です。@Gloopy の回答を参照してください。]

于 2012-09-13T20:36:58.957 に答える