2013-03-13 22 views
28

AngularJSには、角度のDocsで述べたように、DOMベースのコントローラ継承があります。AngularJSコントローラの継承

<div ng-controller="BaseController"> 
    <p>Base Controller Value: {{value}}</p> 
    <button ng-click="updateValue()">Update In Base</button> 
    <div ng-controller="DerivedController"> 
     <p>Derived Controller Value: {{value}}</p> 
     <button ng-click="updateValue()">Update In Derived</button> 
    </div> 
</div> 

scope変数 "value"は、BaseControllerにのみ存在します。これに基づいて、BaseControllerまたはDerivedControllerのメソッドで値を変更しながら、両方の値を更新する必要があります。しかし、個々のスコープ変数だけが更新されます。

は、ここで同じ例を実証フィドルです:http://jsfiddle.net/6df6S/1/レベルでの変化は、直接の子と現在のスコープの直接の親に伝播させることができ、どのよう

我々は

$スコープを使用してこれを実装することができます。$

を見てか、そのようなウォッチャーを使用せずにこれを行うにはどのような方法がありますか?

編集1:

$スコープを使用することでは$ここで見て、私は、私は価値がこのようなメカニズムを使用せずにすべてのスコープ間で更新になるだろうする方法を模索していた

$scope.$watch("value", function() { 
    $scope.$broadcast("childChangeListener"); //Downwards to all children scopes 
    $scope.$emit("parentChangeListener"); //Upwards to all parent scopes 
}); 

を意味したものです。

+0

$ rootScope –

+0

を使用してください。$ rootScopeにプロパティとメソッドを入れずに$ scopeを共有する方法はありますか? –

+4

$ rootScopeは使用しないでください。コントローラ間でデータを共有する代わりにサービスを使用してください(私の答えを参照)。 –

答えて

2

$放送方法を見て取る:ドキュメントから$broadcast

を:

登録NGを通知するすべての子スコープ(およびその 子供)に下向きにイベント名をディスパッチ

$ rootScope。リスナーで.Scope#$

+0

ありがとうブルーノ。しかし、 "値"を監視することで、この "値"に無関係であっても、すべてのダイジェストサイクルの一部としてウォッチ変数が検証されるため、 "値"が変更されたかどうかを確認するために、 –

+0

'$ rootscope'でサービスを選択する特別な理由はありますか? –

5

子コントローラの文字列値を直接参照することはできません。プロトタイプの継承のため、子スコープ(子コントローラを使用するときに作成される)のプロパティvalueを設定すると、親スコーププロパティを更新するのではなく、子スコープでそのプロパティが作成されます。

スコープはモデルではないため、多くのプロパティを持つ変数を汚染しないようにしてください。モデルオブジェクトを作成し、それにサブプロパティを作成します。このオブジェクトは子コントローラ\ scopeに渡すことができます。

jsfiddleに上記の点を説明しました。

また、このwiki pageを試して、プロトタイプの継承の厄介さを理解することを強くお勧めします。

+2

+1ですが、スコープ継承を提供する特定のHTML構造に頼るのではなく、サービス間でデータを共有することをお勧めします(私の答えを参照)。 –

49

複数のコントローラが同じデータにアクセスする必要がある場合は、serviceを使用する必要があります。スコープ継承は、HTMLの記述方法を制限するので、スコープの継承に頼るべきではありません。たとえば、DerivedControllerをBaseControllerの子にすべきではないと判断しました。

サービスでは通常、パブリックAPIを提供し、実装を非表示にする必要があります。これにより、内部をリファクタリングするのが容易になります。

HTML:

<div ng-controller="BaseController"> 
    <p>Base Controller Value: {{model.getValue()}}</p> 
    <button ng-click="model.updateValue('Value updated from Base')">Update In Base</button> 
    <div ng-controller="DerivedController"> 
     <p>Derived Controller Value: {{model.getValue()}}</p> 
     <button ng-click="model.updateValue('Value updated from Derived')">Update In Derived</button> 
    </div> 
</div> 

はJavaScript:

app.factory('sharedModel', function() { 
    // private stuff 
    var model = { 
     value: "initial Value" 
    }; 
    // public API 
    return { 
     getValue: function() { 
      return model.value; 
     }, 
     updateValue: function(value) { 
      model.value = value; 
     } 
    }; 
}); 

function BaseController($scope, sharedModel) { 
    $scope.model = sharedModel; 
} 

function DerivedController($scope, sharedModel) { 
    $scope.model = sharedModel; 
} 

Fiddle

また、$ rootScopeをコントローラ間で共有することはお勧めしません。

+0

私はあなたの意見を見ますが、この方法は非常に冗長であるようです。更新メソッドを使用せずに、サービスから返されたモデルを更新することはできませんか? – Chandermani

+1

ちょうどあなたが私を救ったと言っています:) –

+0

@Chandermani:私は同意すると、ここのサービスを使うことは控えめだと思います。 HTML構造に依存しない方法でコントローラの継承を行う方法については、この回答を見てください:http://stackoverflow.com/a/20230720/62571 – cdmckay

8

あなたのフィドルのバインディングは、範囲内のプロパティに直接あります。必要な継承は、スコープ内のオブジェクトにデータをバインドすることで実現できます。

http://jsfiddle.net/2Dtyq/

scope.shared = {}  
scope.shared.value = "Something" 

だけではなく

scope.value= "Something" 

何が起こっていますか?
DerivedControllerが構築されている間、プロトタイプで渡されるスコープはBaseControllerのスコープを継承します。
DerivedControllerのスコープオブジェクトには、依然として "value"という独自のプロパティがありません。したがって、親のスコープから取得したプロパティにバインドされます。
アップデートベースでボタンをクリックすると、両方のバインディングに反映されます。 ボタンをクリックすると、DerviedControllerのスコープに「value」という名前の新しいプロパティが作成されます。そのため、親のvalueプロパティへのバインドは中断されます。 ベースでの更新のクリックは、2番目のデータバインディングをリフレッシュしません。
別のオブジェクトに配置すると、新しいプロパティが作成されないようになり、継承は引き続き維持されます。

+0

これと@ Chandermaniの答えが正解です。ここに示されている他のソリューションは回避策ですが、動作の根本原因を特定するものではありません。 – do0g

0

プリミティブ値の代わりにオブジェクトを使用します。あなたの場合、このようなオブジェクトを定義してください。

$scope.obj = {"value":"base"}; 

とtry(obj.value)を試してみてください。それが動作します。

+0

$ scope.obj = {"value": "base"}を意味しましたか?私には有効なJSのようには見えません。 –

+0

@halkeyeええ、すみません。それを変更しました。ありがとう! –

0

これは、ngControllerが新しい$ scopeを作成し、valueの参照が同じではないために起こります。 あなたがそのような$parentプロパティを使用していることを解決することができます。

<div ng-controller="BaseController"> 
    <p>Base Controller Value: {{value}}</p> 
    <div ng-controller="DerivedController"> 
     <p>Derived Controller Value: {{$parent.value}}</p> 
    </div> 
</div> 

をそしてDerivedControllerにあなたがそのようなものを使用することができます:$scope.$parent.value

しかし、それはcontrollerAs構文を使用することを実現するための最良の方法を。

そして、あなたがそのようなものを使用することができますDerivedControllerで

<div ng-controller="BaseController as BaseController "> 
<p>Base Controller Value: {{BaseController.value}}</p> 
<div ng-controller="DerivedController"> 
    <p>Derived Controller Value: {{BaseController.value}}</p> 
</div> 
:あなたが参照しているコントローラが何であるかを知っているので、コードより可読性に与える $scope.BaseController.value

。 その詳細についてngController DocsまたはDigging into Angular’s “Controller as” syntax by ToddMotto