2013-06-19 13 views
10

詳細が必要な場合や、何かを明確にしたい場合はお知らせください。私はこれを理解するためにさまざまなことを試みましたが、解決策は見つかりませんでした。AngularJSネストされたディレクティブでの双方向データのバインド

私はangularJSには比較的新しいので、いくつかのレイヤーのデータでアプリを構築しようとしています。私はいくつかの基本的なユーザ情報をController PageControllerのボディのスコープに格納しています。次に、テンプレート用のカスタムディレクティブを含む$ routeParams(コントローラSettingsController)を使用して読み込む設定フォームを作成します。ディレクティブはネストされているので、最初のものの中に2番目のものをロードするためにtransclusionを使用しています。これはすべて問題なく動作しているようです。

私の問題は、最も内側のディレクティブ内からフィールドuser.firstnameを参照しようとしており、双方向データバインディングを使用して、PageControllerスコープの値も変更されるようにするためです。私は、これらの種類の問題の多くは、ngモデルのプリミティブを使用することによって発生することを知っていますが、私は余分なオブジェクトの中にすべてを入れてみましたので、プロトタイプの継承を無効にしました。私はここで間違って何をしていますか?

私のコードのJSFiddleは、できるだけ問題を切り分けるために削除されました。この例では、PageControllerスコープに直接ある外部テキストボックスを入力すると、そのテキストボックスが変更されるまで内部のテキストボックスが変更され、その上で接続が切断されます。これは他の質問に記述されているようにプリミティブを使用する問題と同じように思えますが、ここでどこに問題があるのか​​わかりません。

HTML:

<body class="event-listing" ng-app="app" ng-controller="PageController"> 
    <div class="listing-event-wrap"> 
     <input type="text" ng-model="user.firstname" /> 
     <div ng-controller="SettingsController"> 
      <section block title="{{data.updateInfo.title}}" description="{{data.updateInfo.description}}"> 
       <div formrow label="{{data.updateInfo.labels.firstname}}" type="textInput" value="user.firstname"></div> 
      </section> 
     </div> 
    </div> 
</body> 

角度指令:

app.directive('formrow', function() { 
return { 
    scope: { 
      label: "@label", 
      type: "@type", 
      value: "=value" 
    }, 
    replace: true, 
    template: '<div class="form-row">' + 
      '<div class="form-label" data-ng-show="label">{{label}}</div>' + 
      '<div class="form-entry" ng-switch on="type">' + 
       '<input type="text" ng-model="value" data-ng-switch-when="textInput" />' + 
      '</div>' + 
     '</div>' 
} 
}); 
app.directive('block', function() { 
return { 
    scope: { 
      title: "@title", 
      description: "@description" 
    }, 
    transclude: true, 
    replace: true, 
    template: '<div class="page-block">' + 
      '<h2 data-ng-show="title">{{title}}</h2>' + 
      '<p class="form-description" data-ng-show="description">{{description}}</p>' + 
      '<div class="block-inside" data-ng-transclude></div>' + 
      '</div>' 
} 
}); 

角度コントローラ:

app.controller("PageController", function($scope) { 
    $scope.user = { 
     firstname: "John" 
    }; 
}); 
app.controller("SettingsController", function($scope) { 
    $scope.data = { 
     updateInfo: { 
      title: "Update Your Information", 
      description: "A description here", 
      labels: { 
       firstname: "First Name" 
      } 
     } 
    } 
}); 

答えて

9

私はそうです前のコードを実行してください。代わりにこれを試してください:http://jsfiddle.net/CxNc2/2/

実際の値を渡す代わりに、私は今オブジェクト+正しい値のポインタを渡しています。 ng-model="value"なくng-model="someobj.somevalue"(ディレクティブでテキストボックスは、そのモデルの代わりにオブジェクトのプリミティブを使用しているため

app.directive('formrow', function() { 
    return { 
     scope: { 
      label: "@label", 
      type: "@type", 
      value: "@value", 
      refobj: "=" 
     }, 
     replace: true, 
     template: '<div class="form-row">' + 
      '<div class="form-label" data-ng-show="label">{{label}}</div>' + 
      '<div class="form-entry" ng-switch on="type">' + 
     '<input type="text" ng-model="refobj[value]" data-ng-switch-when="textInput" />' + 
      '</div>' + 
     '</div>' 
    } 
+0

このような迅速な対応に感謝します。私はフィドルを試しましたが、私が投稿したのと同じことをするようです。スコープを機能分離スコープに変更する目標は何ですか? – princjef

+0

refobjを追加したので、ディレクティブ内で 'firstname'を呼び出す必要はありません。これは一般的なものにしたいと思っています。 – Nir

+0

それは本当に賢いです!ドットの代わりに配列表記を使うことは考えていませんでした。これは私のニーズに対応します。ありがとう! – princjef

8

<body class="event-listing" ng-app="app" ng-controller="PageController"> 
    <div class="listing-event-wrap"> 
     <input type="text" ng-model="user.firstname" /> 
     <div ng-controller="SettingsController"> 
      <section block title="{{data.updateInfo.title}}" description="{{data.updateInfo.description}}"> 
       <div formrow label="{{data.updateInfo.labels.firstname}}" type="textInput" refobj='user' value="firstname"></div> 
      </section> 
     </div> 
    </div> 
</body> 

と私はここrefobj +付加価値:私はここ「refobject」を追加しました)、そのモデルはローカルスコープでのみ作成され、親はそれにアクセスできません。

修正は、オブジェクトのプロパティとしてdot ruleを用いて指示テキストボックスモデルを定義することである。

ng-model="value.firstname" 

そしてだけではなくプリミティブプロパティの指令に全体userオブジェクトを渡す:

<div formrow ... value="user"></div> 

Here is a demo

+0

ああ、どこが間違っているのか分かります。洞察に感謝します – princjef

+0

ねえ、私は事をより明確に見るためにあなたのデモを単純化しました。それは複雑なオブジェクトでは動作するようですが、単純なプロパティでは動作しません... [こちらは更新版です](http://jsfiddle.net/BXRnM/4/)。なぜ見えますか? – Dmitry

+0

@Dmitryあなたの単純なプロパティの例は、OPのエラーを再導入します。簡単に言えば、Angular scope継承_では、単純なプリミティブ変数ではなくオブジェクトが必要です。これは、JavaScriptのプロトタイプ継承の直接的な結果です。あなたは[[この回答](http://stackoverflow.com/questions/16928341/update-parent-scope-variable/16929117#16929117)を見てみることができます]私は別の例を見たり、[[this Q&A](http://stackoverflow.com/questions/14049480/what-are-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs)]を参照してください。 – sh0ber

0

問題i sがng-switchによって引き起こされた場合、gitのdoc Understanding scopeから。

ng-switchスコープの継承は、ng-includeのように機能します。したがって、親スコープのプリミティブへの 双方向データバインディングが必要な場合は、$ parentを使用するか、 モデルをオブジェクトに変更してから、 オブジェクトのプロパティにバインドします。これにより、親スコープ のプロパティの子スコープ隠蔽/シャドーイングが回避されます。

テキストボックスにテキストを入力すると、コード がng-switchスコープに対して実行されます。

$scope.value="the text you typed"

ng-switchスコープのための新しいプロパティを作成しますので、それは、value .thisを検索するプロトタイプチェーンに相談しないであろう。

これはどのように証言するのですか?

value$parent.valueに変更した場合。すべて正常に動作します。プリミティブ型の場合はng-switchであるため(angularjsはvalueをプリミティブ型として認識します)、$parentformrowディレクティブスコープを参照します。

ng-switchを削除するか、ドキュメントの指示どおりに実行してください。問題は消えます。

さらに重要なことに、文書では、双方向バインディングを適用するときに常に.のドットを使用してモデルを参照することをお勧めします。

もし私が何か間違っていたら。私を親切に修正して、それを正しくしてください。

関連する問題