web-dev-qa-db-ja.com

ng-includeを使用するとスコープが失われる

このモジュールルートがあります。

var mainModule = angular.module('lpConnect', []).
    config(['$routeProvider', function ($routeProvider) {
    $routeProvider.
        when('/home', {template:'views/home.html', controller:HomeCtrl}).
        when('/admin', {template:'views/admin.html', controller:AdminCtrl}).
        otherwise({redirectTo:'/connect'});
}]);

ホームHTML:

<div ng-include src="views.partial1"></div>

partial1 HTML:

<form ng-submit="addLine()">
    <input type="text" ng-model="lineText" size="30" placeholder="Type your message here">
</form>

HomeCtrl

function HomeCtrl($scope, $location, $window, $http, Common) {
    ...
    $scope.views = {
        partial1:"views/partial1.html"
    };

    $scope.addLine = function () {
        $scope.chat.addLine($scope.lineText);
        $scope.lines.Push({text:$scope.lineText});
        $scope.lineText = "";
    };
...
}

addLine関数$scope.lineTextundefinedで、これはng-controller="HomeCtrl"partial1.htmlに追加することで解決できますが、コントローラーが2回呼び出されます。ここに何が欠けていますか?

179
Shlomi Schwartz

これは、ng-includeが新しい子スコープを作成するためです。したがって、$scope.lineTextは変更されません。 thisは現在のスコープを参照しているので、this.lineTextを設定する必要があると思います。

81

@Renanが述べたように、ng-includeは新しい子スコープを作成します。このスコープは、HomeCtrlスコープからプロトタイプを継承します(下の破線を参照)。 ng-model="lineText"は、HomeCtrlのスコープではなく、子スコープにプリミティブスコーププロパティを実際に作成します。この子スコープは、親/ HomeCtrlスコープからアクセスできません。

ng-include scope

ユーザーがHomeCtrlの$ scope.lines配列に入力した内容を保存するには、値をaddLine関数に渡すことをお勧めします。

 <form ng-submit="addLine(lineText)">

さらに、lineTextはngIncludeスコープ/部分によって所有されているので、それをクリアする責任があるはずです。

 <form ng-submit="addLine(lineText); lineText=''">

したがって、関数addLine()は次のようになります。

$scope.addLine = function(lineText) {
    $scope.chat.addLine(lineText);
    $scope.lines.Push({
        text: lineText
    });
};

フィドル

代替案:

  • homeCtrlの$ scopeでオブジェクトプロパティを定義し、それをパーシャルで使用します:ng-model="someObj.lineText; フィドル
  • 推奨されません。これはハックです。パーシャルで$ parentを使用して、HomeCtrl $ scopeのlineTextプロパティを作成/アクセスします。:ng-model="$parent.lineText"; フィドル

上記の2つの選択肢がなぜ機能するのかを説明するのは少し複雑ですが、ここでは完全に説明されています: AngularJSのスコーププロトタイプ/プロトタイプ継承のニュアンスは何ですか?

AddLine()関数でthisを使用することはお勧めしません。どのスコープがアクセス/操作されているかは、それほど明確ではありません。

257
Mark Rajcok

受け入れられた答えが示すようにthisを使用する代わりに、代わりに$parentを使用します。あなたのpartial1.htmlには次のものがあります:

<form ng-submit="$parent.addLine()">
    <input type="text" ng-model="$parent.lineText" size="30" placeholder="Type your message here">
</form>

ng-includeまたは他のディレクティブでスコープの詳細を知りたい場合は、これをチェックしてください: https://github.com/angular/angular.js/wiki/Understanding-Scopes#ng-include

32
ErwinGO

親スコープとサブスコープのデータを混在させずにこの問題を回避する方法を見つけました。 ng-if要素にng-includeを設定し、スコープ変数に設定します。例えば ​​:

<div ng-include="{{ template }}" ng-if="show"/>

コントローラーで、必要なすべてのデータをサブスコープに設定したら、showをtrueに設定します。 ng-includeは、この時点でスコープ内のデータセットをコピーし、サブスコープ内に設定します。

経験則では、スコープのデータをスコープの範囲内で深くすることです。それ以外の場合は、この状況になります。

マックス

3
wascou