Das Ng-Modell aktualisiert den Controller-Wert nicht

270

Wahrscheinlich dumme Frage, aber ich habe mein HTML-Formular mit einfacher Eingabe und Schaltfläche:

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

Dann im Controller (Vorlage und Controller werden von routeProvider aufgerufen):

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

Warum wird die Ansicht in der Konsole korrekt aktualisiert, aber nicht definiert, wenn Sie auf die Schaltfläche klicken?

Vielen Dank!

Update: Scheint, als hätte ich dieses Problem tatsächlich gelöst (bevor ich einige Problemumgehungen finden musste) mit: Ich musste nur meinen Eigenschaftsnamen von searchTextin ändern search.text, dann ein leeres $scope.search = {};Objekt im Controller definieren und voila ... Ich habe keine Ahnung, warum es funktioniert obwohl;]

Alchemie
quelle
Sind Sie sicher, dass Sie diesen Controller in diesem Teil des Dokuments verwenden? Können Sie ein Beispiel für einen minimalen Fehler veröffentlichen?
wroniasty
1
Ja, 100% sicher, dass der Controller in Ordnung ist, dieses Problem scheint mir vertraut zu sein ... Überraschenderweise funktioniert es, wenn ich den Eigenschaftsnamen von searchTextin ändere. search.textIrgendeine Idee warum?
Alchemie
4
@Arthur: Es ist ein bisschen nicht offensichtlich, aber ng-model erstellt in Ihrer Ansicht nur eine Art lokale Sprachvariable. Wenn Sie es also so halten möchten, müssen Sie es an die Funktion check () übergeben, wie zum Beispiel: check ( searchText) und Ihr Controller erkennt es dann. Hoffe es hilft
Alchemie
3
Für das Protokoll, ist es geschrieben voila, nicht vuala, wollausw.
Dan Bechard
3
Ich denke, die Antwort, die Sie suchen, ist auf stackoverflow.com/a/14049482/1217913
Willa

Antworten:

71

Controller als Version (empfohlen)

Hier die Vorlage

<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>

Die JS

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

Ein Beispiel: http://codepen.io/Damax/pen/rjawoO

Am besten verwenden Sie Komponenten mit Angular 2.x oder Angular 1.5 oder höher

########

Alter Weg (NICHT empfohlen)

Dies wird NICHT empfohlen, da eine Zeichenfolge ein Grundelement ist. Es wird dringend empfohlen, stattdessen ein Objekt zu verwenden

Versuchen Sie dies in Ihrem Markup

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

und das in Ihrem Controller

$scope.check = function (searchText) {
    console.log(searchText);
}
Damax
quelle
17
Dies funktioniert nur in eine Richtung ... was ist, wenn Sie den Wert von ändern möchten searchText?
CDMckay
199
Dies beantwortet auch nicht das "Warum?" Frage.
CDMckay
4
Was ist, wenn ich keine Schaltfläche verwenden möchte? Ich muss zum Beispiel bei
Enter
2
Saniko => Um bei der Eingabe einzureichen, müssen Sie das Formular-Tag verwenden und ng- submit darauf ( docs.angularjs.org/api/ng.directive:ngSubmit )
Damax
1
@ HP's411, weil ein String ein Grundelement ist. Wenn Angular den Wert zuweist, ändert es den Zeiger auf den Wert, sodass der Controller den alten Wert betrachtet, da er den alten Zeiger auf den Wert hat.
Damax
620

"Wenn Sie ng-model verwenden, müssen Sie einen Punkt darin haben."
Stellen Sie Ihr Modell auf eine object.property und Sie können loslegen.

Regler

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

Vorlage

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

Dies geschieht, wenn untergeordnete Bereiche im Spiel sind - wie untergeordnete Routen oder ng-Wiederholungen. Der untergeordnete Bereich erstellt seinen eigenen Wert und ein Namenskonflikt entsteht wie hier dargestellt :

Weitere Informationen finden Sie in diesem Videoclip: https://www.youtube.com/watch?v=SBwoFkRjZvE&t=3m15s

Will Stern
quelle
94
Das ist die wahre Antwort.
Keslert
16
@Catfish Bei prototypischer Vererbung ist die Referenz / Verbindung zur übergeordneten Eigenschaft nicht mehr vorhanden, wenn Sie in die untergeordnete Eigenschaft schreiben. So wie Angular Scopes-Modelle, wenn Sie keinen Punkt haben, wird eine neue Eigenschaft in Ihrem untergeordneten Bereich erstellt. Dieses Video erklärt es ausführlicher: youtube.com/watch?v=ZhfUv0spHCY&feature=youtu.be&t=30m
Will Stern
1
Gracias Boss. Das ist wahr! Es scheint jedoch keine konsequente Eigenart zu sein, da ich das Problem nur bei Verwendung mit dem ionischen Framework habe
Don Barry,
6
@ user3677331 Es funktioniert ohne Punkt, bis Sie einen untergeordneten Bereich haben, der versucht, mit ihm zu sprechen (wie zum Beispiel ein Element innerhalb einer ng-Wiederholung). Angenommen, Ihr Modellname war "Telefon". Ihr untergeordneter Bereich erstellt "Telefon". Dann tritt ein Bereichskonflikt auf, da der untergeordnete Bereich eine "Telefon" -Variable hat und daher nicht auf "Telefon" im übergeordneten Bereich zugreifen kann. Wenn der untergeordnete Bereich user.phone erstellt, wird er dem übergeordneten Benutzerobjekt hinzugefügt, sodass beide Bereiche auf dasselbe Objekt zeigen
Will Stern
3
Sehr hilfreich. Ich war mir nicht sicher, ob ich eine Antwort auf eine relativ vage Frage finden würde, aber das war tot.
CodeManiak
57

In Mastering Web Application Development mit AngularJS Buch S.19 wird geschrieben, dass

Vermeiden Sie direkte Bindungen an die Eigenschaften des Bereichs. Die bidirektionale Datenbindung an Objekteigenschaften (in einem Bereich verfügbar gemacht) ist ein bevorzugter Ansatz. Als Faustregel sollte ein Punkt in einem Ausdruck enthalten sein, der für die Anweisung ng-model bereitgestellt wird (z. B. ng-model = "thing.name").

Bereiche sind nur JavaScript-Objekte und ahmen die Dom-Hierarchie nach. Gemäß JavaScript Prototype Inheritance werden die Eigenschaften von Bereichen durch Bereiche getrennt. Um dies zu vermeiden, sollte die Punktnotation zum Binden von ng-Modellen verwendet werden.

efirat
quelle
2
Vielen Dank für diesen Hinweis. Ich halte dies für einen interessanten Punkt im Zusammenhang mit dem ng-Modell.
Könige
44

Verwenden thisstatt $scopeArbeiten.

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>

Bearbeiten: Zum Zeitpunkt des Schreibens dieser Antwort hatte ich eine viel kompliziertere Situation als diese. Nach den Kommentaren habe ich versucht, es zu reproduzieren, um zu verstehen, warum es funktioniert, aber kein Glück. Ich denke, irgendwie (ich weiß nicht wirklich warum) wird ein neuer untergeordneter Bereich generiert, der thissich auf diesen Bereich bezieht. Wenn $scopees jedoch verwendet wird, bezieht es sich aufgrund der lexikalischen Bereichsfunktion von Javascript tatsächlich auf den übergeordneten $ scope .

Wäre toll, wenn jemand mit diesem Problem auf diese Weise testet und uns informiert.

Feyyaz
quelle
Makellos, du bist ein Genie
fjcero
1
Sieht aus wie die Funktionen befestigt $scopeeinen neuen Bereich erstellt (dh in Funktion check(), thisbezieht sich auf einen Bereich, der ein Kind Umfang ist $scope). Wieso ist es so? Können Sie einige Erklärungen geben?
Xun Yang
1
Warum sollte ich in diesem Fall 'this' anstelle von '$ scope' verwenden? weil es in meinem vorherigen Projekt mit $ scope funktioniert hat, aber diesmal funktioniert dasselbe nicht mit $ scope. Aber 'das' hat funktioniert. Warum ist das so?
Rashedul.Rubel
Dies funktioniert, aber wenn Sie sagen this.searchText = "something else"oder sogar wenn $scope.searchText = "something else", wird die Ansicht nicht aktualisiert. Können Sie dieses Problem erklären?
Shri
es sollte. Ich habe es mit dem obigen Code versucht, es hat die Ansicht aktualisiert.
Feyyaz
13

Ich hatte das gleiche Problem und es lag daran, dass ich das leere Objekt nicht zuerst oben auf meinem Controller deklarierte:

$scope.model = {}

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

Hoffe das wird bei dir funktionieren!

Millsionaire
quelle
10

Ich bin auf dasselbe Problem gestoßen, als ich mich mit einer nicht trivialen Ansicht befasst habe (es gibt verschachtelte Bereiche). Und schließlich wurde festgestellt, dass dies bei der Entwicklung der AngularJS-Anwendung aufgrund der Art der prototypbasierten Vererbung von Java-Skripten eine schwierige Sache ist. Durch diesen Mechanismus werden verschachtelte AngularJS-Bereiche erstellt. Der aus dem ng-Modell erstellte Wert wird im untergeordneten Bereich platziert, ohne dass der übergeordnete Bereich (möglicherweise der in den Controller eingefügte) den Wert nicht sieht. Der Wert schattiert auch alle Eigenschaften mit demselben Namen, die im übergeordneten Bereich definiert sind, wenn kein Punkt verwendet wird um einen Referenzzugriff für einen Prototyp zu erzwingen. Weitere Informationen finden Sie im Online-Video http://egghead.io/video/angularjs-the-dot/ und in den Kommentaren , die dieses Problem veranschaulichen .

Roger Jin
quelle
6

Schauen Sie sich diese Geige an http://jsfiddle.net/ganarajpr/MSjqL/

Ich habe (ich nehme an!) Genau das getan, was Sie getan haben, und es scheint zu funktionieren. Können Sie überprüfen, was hier für Sie nicht funktioniert?

Ganaraj
quelle
Hmmmm ... danke, dass Sie sich damit befasst haben, ich würde annehmen, dass es funktionieren sollte ... warum funktioniert es nicht für mich? Und was ist wichtiger: Warum funktioniert es mit Objekten und nicht mit einfachen Stringvariablen? Vielleicht, weil ich meine Controller im routeProvider in unangemessener Weise verweise? Ich habe versucht, Globals zu vermeiden, und habe meine Controller als modulename.ctrlName in die Datei controller.js eingefügt. Könnte das Kopfschmerzen verursachen?
Alchemie
Ich bin mir nicht sicher, warum es bei Ihnen nicht funktioniert. Wenn Sie dieses Problem in einer Geige isolieren könnten, könnte Ihnen
wahrscheinlich
Okay, werde es tun, ich werde gerade die Arbeit beenden, aber ich werde das sicher morgen oder später am Abend tun, Prost! Es könnte ein Problem mit der Art und Weise geben, wie ich meine Strg-Namen benannt habe, wir werden sehen ...
Alchemie
6

Da dies niemand erwähnte, kann das Problem durch Hinzufügen $parentzur gebundenen Eigenschaft gelöst werden

<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>

Und der Controller

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

    $scope.BankLogin = function () {
        console.log($scope.ssn); // works!
    };
}]);
Eric Herlitz
quelle
danke für die antwort, aber wie funktioniert das? sollte es idealerweise am selben Scope-Element arbeiten und nicht am übergeordneten?
V31
5

Für mich wurde das Problem gelöst, indem meine Daten in einem Objekt gespeichert wurden (hier "Daten").

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'
   }
   

});

Ich hoffe es wird helfen

Plici Stéphane
quelle
3
Wenig vom Thema hier, aber "Daten" ist ein Pluralbegriff für "Datum"
Thethakuri
@thethakuri und "Datum" auf Ungarisch ist "Datum", also würde ich das auch nicht verwenden: P
EpicPandaForce
Ich bevorzuge Waffelhaus gegenüber IHOP
Nico Westerdale
2

Ich hatte gerade genau dieses Problem mit einem root_controller, der an das body-Element gebunden ist. Dann habe ich ng-view mit dem Winkelrouter verwendet. Das Problem ist, dass eckig IMMER einen neuen Bereich erstellt, wenn der HTML-Code in das ng-view-Element eingefügt wird. Infolgedessen wurde meine "Check" -Funktion für den übergeordneten Bereich des Bereichs definiert, der von meinem ng-model-Element geändert wurde.

Um das Problem zu lösen, verwenden Sie einfach einen dedizierten Controller in routengeladenen HTML-Inhalten.

moritz
quelle
2

Sie können dies tun, um die Suche in ng-keypressEingabe für Eingabetext und in ng-clickfür das Symbol zu aktivieren :

<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);
        }
    }
Naoufal Gaffa
quelle
2

Ich hatte das gleiche Problem.
Der richtige Weg wäre, den 'searchText' als eine Eigenschaft innerhalb eines Objekts festzulegen.

Aber was ist, wenn ich es so lassen möchte, wie es ist, eine Schnur? Nun, ich habe jede einzelne hier erwähnte Methode ausprobiert, nichts hat funktioniert.
Aber dann habe ich festgestellt, dass das Problem nur in der Initiierung liegt, also habe ich nur das Wertattribut festgelegt und es hat funktioniert.

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

Auf diese Weise wird der Wert nur auf den Wert '$ scope.searchText' gesetzt und aktualisiert, wenn sich der Eingabewert ändert.

Ich weiß, dass es eine Problemumgehung ist, aber es hat bei mir funktioniert.

Wanderung Nalbandyan
quelle
2

Ich hatte das gleiche Problem ... Die Lösung, die für mich funktioniert hat, ist die Verwendung dieses Schlüsselworts ..........

alert (this.ModelName);

SnktJavaMaster
quelle