Ngモデルはコントローラー値を更新しません


270

おそらくばかげた質問ですが、シンプルな入力とボタンを備えたhtmlフォームがあります:

<input type="text" ng-model="searchText" />
<button ng-click="check()">Check!</button>
{{ searchText }}

次にコントローラーで(テンプレートとコントローラーはrouteProviderから呼び出されます):

$scope.check = function () {
    console.log($scope.searchText);
}

ボタンをクリックすると、コンソールでビューが正しく更新されていても定義されていないのはなぜですか?

ありがとう!

更新:私は実際にその問題を解決したようです(以前にいくつかの回避策を考案する必要がありました)。プロパティ名をからsearchTextに変更し、コントローラでsearch.text空の$scope.search = {};オブジェクトを定義して、出来上がり...なぜそれが機能しているかわからない;]


このドキュメントのこの部分でこのコントローラーを使用していますか?最小限の失敗例を投稿できますか?
wroniasty 2012

1
はい、100%は、必ずコントローラは、その問題が...私にはよく知られているようだ、私はからプロパティ名を変更したときに驚くべきことでは動作しますが、大丈夫ですsearchTextsearch.text、任意のアイデアなぜ?
錬金術2012

4
@Arthur:少し明白ではありませんが、ng-modelはビューに一種の話すローカル変数を作成するだけなので、この方法で保持したい場合は、次のように、check()関数に渡す必要があります。 searchText)とコントローラーがそれを認識します。それがお役に立てば幸い
錬金術2013年

3
記録のために、それはvoilavualawolla
、、、

3
あなたが探している答えは、stackoverflow.com / a / 14049482/1217913
Willa

回答:


71

バージョンとしてのコントローラー(推奨)

ここでテンプレート

<div ng-app="example" ng-controller="myController as $ctrl">
    <input type="text" ng-model="$ctrl.searchText" />
    <button ng-click="$ctrl.check()">Check!</button>
    {{ $ctrl.searchText }}
</div>

JS

angular.module('example', [])
  .controller('myController', function() {
    var vm = this;
    vm.check = function () {
      console.log(vm.searchText);
    };
  });

例:http : //codepen.io/Damax/pen/rjawoO

最良の方法は、Angular 2.xまたはAngular 1.5以上のコンポーネントを使用することです。

########

古い方法(非推奨)

文字列はプリミティブなので、これはお勧めできません。代わりにオブジェクトを使用することを強くお勧めします

マークアップでこれを試してください

<input type="text" ng-model="searchText" />
<button ng-click="check(searchText)">Check!</button>
{{ searchText }}

そしてこれはあなたのコントローラーにあります

$scope.check = function (searchText) {
    console.log(searchText);
}

17
これは一方向でのみ機能します...の値を変更したい場合はどうなりsearchTextますか?
cdmckay 2013

199
これも「なぜ?」には答えません。質問。
cdmckay 2013

4
ボタンを使用したくない場合はどうなりますか?たとえば、入力時に送信する必要があります
danikoren 2014年

2
(Sanikoは=>、入力した上で提出するには、formタグを使用する必要がありますし、それを提出NG docs.angularjs.org/api/ng.directive:ngSubmitを
Damax

1
@ HP's411それは文字列がプリミティブだからです。Angularが値を割り当てると、ポインターが値に変更されます。コントローラーは値への古いポインターを持っているため、コントローラーは古い値を調べます。
Damax

620

「ng-modelを使用する場合、そこにドットが必要です。」
モデルがobject.propertyを指すようにすれば、準備は完了です。

コントローラ

$scope.formData = {};
$scope.check = function () {
  console.log($scope.formData.searchText.$modelValue); //works
}

テンプレート

<input ng-model="formData.searchText"/>
<button ng-click="check()">Check!</button>

これは、子スコープやng-repeatsなどの子スコープが動作しているときに発生します。子スコープが独自の値を作成し、ここに示すように名前の競合が発生します

詳細については、このビデオクリップを参照してください:https : //www.youtube.com/watch?v=SBwoFkRjZvE&t=3m15s


94
これが本当の答えです。
ケスラート2014年

16
@Catfishプロトタイプの継承では、子プロパティに書き込むたびに、親プロパティへの参照/接続が存在しなくなります。Angular Scopesがモデル化する方法で、ドットがない場合、子スコープ内に新しいプロパティが作成されます。この動画では、YouTube.com

1
グラシアスボス。これは本当です!ただし、Ionicフレームワークで使用する場合にのみ問題が発生するため、一貫性のない癖があるように見えます
Don Barry

6
@ user3677331(ng-repeat内のアイテムなどの)それに話しかけようとする子スコープができるまで、ドットなしで正常に動作します。モデル名が「phone」だったとしましょう。子スコープが「phone」を作成すると、子スコープに「phone」変数があり、親スコープの「phone」にアクセスできないため、スコープの競合が発生します。一方、子スコープがuser.phoneを作成する場合、親のユーザーオブジェクトに追加され、両方のスコープが同じオブジェクトを指すようになります
Will Stern

3
非常に役立ちます。比較的あいまいな質問への答えを見つけることができるかどうか確信が持てませんでしたが、これは行き詰まりました。
CodeManiak 2015

57

AngularJSブックのp.19を使用したWebアプリケーション開発の習得では、

スコープのプロパティへの直接バインディングは避けてください。(スコープで公開されている)オブジェクトのプロパティへの双方向のデータバインディングは、推奨されるアプローチです。経験則として、ng-modelディレクティブに提供される式にはドットが必要です(たとえば、ng-model = "thing.name")。

スコープは単なるJavaScriptオブジェクトであり、DOM階層を模倣しています。JavaScript Prototype Inheritanceによると、スコーププロパティはスコープによって分離されます。これを回避するには、ドット表記を使用してngモデルをバインドする必要があります。


2
この参照をありがとう。これは、ng-modelに関連する興味深い点だと思います。
キングス

44

作品のthis代わりに使用$scope

function AppCtrl($scope){
  $scope.searchText = "";
  $scope.check = function () {
    console.log("You typed '" + this.searchText + "'"); // used 'this' instead of $scope
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app>
  <div ng-controller="AppCtrl">
    <input ng-model="searchText"/>
    <button ng-click="check()">Write console log</button>
  </div>
</div>

編集:この回答を書いているとき、私はこれよりはるかに複雑な状況にありました。コメントの後、私はそれがなぜ機能するかを理解するためにそれを再現しようとしましたが、運がありませんでした。新しい子スコープが生成さthisれ、そのスコープを参照しているのはどういうわけか(本当に理由はわかりません)。ただし、$scopeが使用されている場合、JavaScriptの字句スコープ機能により、実際には親$ scopeを参照します。

この問題を抱えている誰かがこの方法でテストを行い、私たちに知らせたら素晴らしいでしょう。


完璧な、あなたは天才だ
fjcero

1
に接続された関数$scopeが新しいスコープを作成するように見えます(つまり、function check()ではthis、の子スコープであるスコープを$scope参照します)。なぜそうなのですか?説明していただけますか?
Xun Yang、

1
この場合、「$ scope」の代わりに「this」を使用する必要があるのはなぜですか?以前のプロジェクトでは$ scopeを使用して機能していましたが、今回は$ scopeを使用しても機能しません。しかし、「これ」は機能しました。何故ですか?
Rashedul.Rubel 2016年

これは機能しますが、あなたが言ったthis.searchText = "something else"場合$scope.searchText = "something else"、またはであった場合でも、ビューは更新されません。この問題を説明できますか?
Shri

そうすべき。上記のコードを使用して試したところ、ビューが更新されました。
Feyyaz

13

私は同じ問題を抱えていましたが、それは私が最初にコントローラーの上部で空のオブジェクトを宣言していないためでした:

$scope.model = {}

<input ng-model="model.firstProperty">

これがうまくいくことを願っています!


10

重要なビュー(ネストされたスコープがある)を扱うときに同じ問題に遭遇しました。そして最後に、これは、AngularJSアプリケーションの開発時に、JavaScriptのプロトタイプベースの継承の性質により、既知のトリッキーなことであることがわかりました。AngularJSのネストされたスコープは、このメカニズムによって作成されます。ng-modelから作成された値は、子スコープに配置され、親スコープ(コントローラーに注入されたもの)には値が表示されません。ドットを使用しない場合、値は親スコープで定義された同じ名前のプロパティもシャドウしますプロトタイプ参照アクセスを実施する。詳細については、この問題を説明するためのオンラインビデオ、http://egghead.io/video/angularjs-the-dot/、およびそれに続くコメントを確認してください。


6

このフィドルを見てくださいhttp://jsfiddle.net/ganarajpr/MSjqL/

私は(私が思うに!)あなたがやっていたことを正確に実行しており、それは機能しているようです。ここで何が機能していないかを確認できますか?


うーん..これを調べてくれてありがとう、私はそれがうまくいくはずだと思います...なぜ私にとってそれはうまくいかないのですか?そして、もっと重要なこと:なぜオブジェクトで動作し、プレーンな文字列変数では動作しないのですか?たぶん、routeProviderで不適切な方法でコントローラーを参照しているのでしょうか?グローバルを回避しようとしていて、コントローラーをmodulename.ctrlNameとしてcontrollers.jsファイルに入れました。頭痛の種ですか?
錬金術2012

なぜうまくいかないのかよくわかりません。この問題を
いじくり回して特定できれ

さて、やります、今は仕事を終えるだけですが、明日か夕方には必ずやります、乾杯!ctrlに名前空間を付けた方法に問題がある可能性があります。表示されます...
alchemication

6

誰もこれについて言及していないので、この問題$parentはバインドされたプロパティに追加することで解決できます

<div ng-controller="LoginController">
    <input type="text" name="login" class="form-control" ng-model="$parent.ssn" ng-pattern="/\d{6,8}-\d{4}|\d{10,12}/" ng-required="true" />
    <button class="button-big" type="submit" ng-click="BankLogin()" ng-disabled="!bankidForm.login.$valid">Logga in</button>
</div>

そしてコントローラー

app.controller("LoginController", ['$scope', function ($scope) {
    $scope.ssn = '';

    $scope.BankLogin = function () {
        console.log($scope.ssn); // works!
    };
}]);

答えてくれてありがとう、しかしこれはうまくいっていますか?理想的には、親ではなく同じスコープ要素で作業する必要がありますか?
V31

5

私にとっては、データをオブジェクト(ここでは「データ」)にストックすることで問題が解決しました。

NgApp.controller('MyController', function($scope) {

   $scope.my_title = ""; // This don't work in ng-click function called

   $scope.datas = {
      'my_title' : "",
   };

   $scope.doAction = function() {
         console.log($scope.my_title); // bad value
         console.log($scope.datas.my_title); // Good Value binded by'ng-model'
   }
   

});

それが役に立てば幸い


3
ここでは少し外れたトピックですが、「データ」は「データム」の複数形の用語です
テタクリ

@thethakuriとハンガリー語の "datum"は "date"なので、どちらも使用しないでしょう:P
EpicPandaForce

IHOPよりもワッフルハウスを好む
ニコウェスターデール2017年

2

body要素にバインドされたroot_controllerを使用してこの問題が発生しました。次に、角度ルーターでng-viewを使用していました。問題は、角度が常にHTMLをng-view要素に挿入するときに新しいスコープを作成することです。その結果、ng-model要素によって変更されたスコープの親スコープで「チェック」関数が定義されました。

この問題を解決するには、ルートロードされたhtmlコンテンツ内で専用コントローラーを使用するだけです。


2

これを行うとng-keypress、入力テキストの入力とng-clickアイコンの検索を有効にできます。

<input type="text" ng-model="searchText" ng-keypress="keyEnter(this,$event)" />
<button ng-click="check(searchText)">Check!</button>

in the controller
$scope.search = function (searchText) {
        console.log(searchText);
    }
    $scope.keyEnter = function (serachText,$event) {
        var keyCode = $event.which || $event.keyCode;
        if (keyCode === 13) {//KeyCode for Enter key
           console.log(searchText);
        }
    }

2

私も同じ問題を抱えていました。
適切な方法は、「searchText」をオブジェクト内のプロパティに設定することです。

しかし、文字列をそのままにしたい場合はどうなりますか?さて、私はここで述べられたすべての方法を試しました、何もうまくいきませんでした。
しかし、問題はイニシエーションのみにあることに気付いたので、value属性を設定しただけで機能しました。

<input type="text" ng-model="searchText" value={{searchText}} />

このようにして、値は '$ scope.searchText'値に設定され、入力値が変更されると更新されます。

私はそれが回避策であることを知っていますが、私にとってはうまくいきました。


2

私は同じ問題に直面していました...私のために働いた解決策はこのキーワードを使用することです..........

alert(this.ModelName);

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.