52

ここに私の plnkr があります: http://plnkr.co/edit/n8cRXwIpHJw3jUpL8PX5?p=preview li 要素をクリックする必要があり、フォームが表示されます。ランダムな文字列を入力して「通知を追加」を押します。テキストエリアのテキストの代わりに、未定義になります。

マークアップ:

<ul>
    <li ng-repeat="ticket in tickets" ng-click="select(ticket)">
         {{ ticket.text }}
    </li>
</ul>
<div ui-if="selectedTicket != null">
     <form ng-submit="createNotice(selectedTicket)">
        <textarea ng-model="noticeText"></textarea>
        <button type="submit">add notice</button>
    </form>
</div>

JS 部分:

$scope.createNotice = function(ticket){
   alert($scope.noticeText);
}

「未定義」を返します。angular-ui の ui-if を使用すると、これが機能しないことに気付きました。これが機能しない理由はありますか?修正方法は?

4

4 に答える 4

68

この問題はng-if、テキストエリア要素を囲む要素でディレクティブを使用していないときに発生しました。Mathew の解決策は正しいですが、理由は別のようです。その問題を検索するとこの投稿が指摘されるので、これを共有することにしました。

https://docs.angularjs.org/api/ng/directive/textareaにある AngularJS のドキュメントを見ると、Angular がデフォルトの HTML要素<textarea>を「オーバーライド」する独自のディレクティブを追加していることがわかります。textareaこれは、全体の混乱を引き起こす新しいスコープです。

次のような変数がある場合

$scope.myText = 'Dummy text';

textareaあなたのコントローラーで、それをこのような要素にバインドします

<textarea ng-model="myText"></textarea>

AngularJS は、ディレクティブのスコープでその変数を探します。そこにないので、彼は $parent まで歩いて行きます。そこに変数が存在し、テキストが に挿入されますtextarea。のテキストを変更する場合textarea、Angular は親の変数を変更しません。代わりに、ディレクティブのスコープに新しい変数を作成するため、元の変数は更新されません。Mathew が示唆するように、親の変数にバインドtextareaすると、Angular は常に正しい変数にバインドされ、問題はなくなります。

<textarea ng-model="$parent.myText"></textarea>

これが、この質問に来る他の人々のために物事を解決し、「WTF、私の場合、ng-ifまたは他のディレクティブを使用していない!」と考えることを願っています。私が最初にここに着陸したときのように;)

更新: controller-as 構文を使用する

ずっと前にこれを追加したかったのですが、それを行う時間がありませんでした。これはコントローラーを構築する最新のスタイルであり、上記のものの代わりに使用する必要があり$parentます。その方法理由については、以下をお読みください。

AngularJS 1.2 以降、オブジェクトを使用する代わりにコントローラー オブジェクトを直接参照する機能があり$scopeます。これは、HTML マークアップで次の構文を使用することで実現できます。

<div ng-controller="MyController as myc"> [...] </div>

一般的なルーティング モジュール (つまり、UI ルーター) は、状態に対して同様のプロパティを提供します。UI ルーターの場合、状態定義で次を使用します。

[...]
controller: "MyController",
controllerAs: "myc",
[...]

これにより、ネストされたスコープや誤ってアドレス指定されたスコープの問題を回避できます。上記の例は、このように構築されます。まず JavaScript の部分。簡単に言えば、$scope参照を使用してテキストを設定するのではなくthis、プロパティをコントローラー オブジェクトに直接アタッチするだけです。

angular.module('myApp').controller('MyController', function () {
    this.myText = 'Dummy text';
});

with controller-as 構文のマークアップは次のtextareaようになります。

<textarea ng-model="myc.myText"></textarea>

これは、ネストされたスコープの問題を解決し、特定の時点でのレイヤーの深さをカウントするため、今日このようなことを行う最も効率的な方法です。スコープを参照する古い方法を使用している場合、ディレクティブを使用して要素内で複数のネストされたディレクティブを使用すると、ng-controllerこのような問題が発生する可能性がありました。そして、誰も本当に一日中それをしたくありません!

<textarea ng-model="$parent.$parent.$parent.$parent.myText"></textarea>
于 2014-11-20T13:30:23.020 に答える