web-dev-qa-db-fra.com

Ng-model ne met pas à jour la valeur du contrôleur

Probablement question idiote, mais j'ai mon formulaire HTML avec une simple saisie et un bouton:

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

Ensuite, dans le contrôleur (le modèle et le contrôleur sont appelés depuis routeProvider):

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

Pourquoi la vue est-elle mise à jour correctement mais non définie dans la console lorsque je clique sur le bouton?

Merci!

Mise à jour: On dirait que j'ai en fait résolu ce problème (auparavant, il fallait trouver des solutions) avec: Il suffisait de changer le nom de ma propriété de searchText à search.text, puis de définir vide $scope.search = {}; objet dans le contrôleur et le tour est joué ... Je ne sais pas pourquoi cela fonctionne bien;]

264
alchemication

Contrôleur en version (recommandé)

Ici le modèle

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

Le JS

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

Un exemple: http://codepen.io/Damax/pen/rjawoO

Le mieux sera d’utiliser un composant avec Angular 2.x ou Angular 1.5 ou supérieur

Ancien moyen (NON recommandé)

Ceci n'est PAS recommandé car une chaîne est une primitive, il est fortement recommandé d'utiliser un objet à la place.

Essayez ceci dans votre balisage

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

et cela dans votre contrôleur

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

"Si vous utilisez ng-model, vous devez y placer un point."
Faites pointer votre modèle vers une propriété objet et vous serez prêt à partir.

Contrôleur

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

Modèle

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

Cela se produit lorsque des gammes enfants sont en jeu, comme des routes enfants ou des répétitions ng. La portée enfant crée sa propre valeur et un conflit de noms est né comme illustré ici :

Voir ce clip vidéo pour en savoir plus: https://www.youtube.com/watch?v=SBwoFkRjZvE&t=3m15s

600
Will Stern

Dans Mastering Web Application Development avec AngularJS, livre p.19, il est écrit que

Évitez les liaisons directes aux propriétés de l'étendue. La liaison de données bidirectionnelle aux propriétés de l'objet (exposées sur une étendue) est une approche recommandée. En règle générale, vous devez insérer un point dans une expression fournie à la directive ng-model (par exemple, ng-model = "thing.name").

Les portées ne sont que des objets JavaScript, et elles imitent la hiérarchie dom. Selon héritage du prototype JavaScript , les propriétés des portées sont séparées par des portées. Pour éviter cela, la notation par points devrait utiliser pour lier les modèles ng.

56
efirat

Utiliser this au lieu de $scope fonctionne.

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>

Edit: Au moment d'écrire cette réponse, j'avais une situation beaucoup plus compliquée que celle-là. Après les commentaires, j'ai essayé de le reproduire pour comprendre pourquoi cela fonctionne, mais pas de chance. Je pense en quelque sorte (je ne sais pas vraiment pourquoi) une nouvelle portée enfant est générée et this fait référence à cette portée. Mais si $scope est utilisé, il fait en fait référence à la portée de $ parent en raison de la fonctionnalité portée lexicale de javascript.

Ce serait génial si quelqu'un ayant ce problème teste de cette façon et nous en informe.

43
Feyyaz

J'ai eu le même problème et c'est parce que je n'ai pas déclaré l'objet vierge en haut de mon contrôleur:

$scope.model = {}

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

J'espère que cela fonctionnera pour vous!

12
Millsionaire

J'ai rencontré le même problème lorsqu'il s'agissait d'une vue non triviale (il y a des portées imbriquées). Et finalement découvert que c’est une chose délicate connue lors du développement d’une application AngularJS en raison de la nature de l’héritage du script Java basé sur un prototype. Les portées imbriquées AngularJS sont créées via ce mécanisme. Et la valeur créée à partir de ng-model est placée dans la portée des enfants. Cela ne signifie pas que la portée parent (peut-être celle injectée dans le contrôleur) ne verra pas la valeur, la valeur occultera également toute propriété du même nom définie dans la portée parent si elle n'est pas utilisée pour appliquer un prototype d'accès de référence. Pour plus de détails, consultez la vidéo en ligne spécifique pour illustrer ce problème, http://egghead.io/video/angularjs-the-dot/ et les commentaires qui ont suivi.

10
Roger Jin

Regardez ce violon http://jsfiddle.net/ganarajpr/MSjqL/

J'ai (je suppose!) Fait exactement ce que vous faisiez et cela semble fonctionner. Pouvez-vous vérifier ce qui ne fonctionne pas ici pour vous?

6
ganaraj

Comme personne ne l’a mentionné, le problème peut être résolu en ajoutant $parent à la propriété liée.

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

Et le contrôleur

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

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

Pour moi, le problème a été résolu en stockant mes données dans un objet (ici "données").

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

});

J'espère que ça va aider

5
Plici Stéphane

Je viens d'avoir ce problème en utilisant un root_controller lié à l'élément body. Ensuite, j'utilisais ng-view avec le routeur angular. Le problème est que angular TOUJOURS crée une nouvelle portée lorsqu'il insère le code HTML dans l'élément ng-view. En conséquence, ma fonction "check" a été définie sur la portée parente de la portée modifiée par mon élément ng-model.

Pour résoudre le problème, utilisez simplement un contrôleur dédié dans le contenu HTML chargé par route.

2
moritz

Vous pouvez le faire pour activer la recherche dans ng-keypress à saisir pour le texte saisi et dans ng-click pour l’icône:

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

Je faisais face au même problème ... La solution qui a fonctionné pour moi est d'utiliser ce mot clé ..........

alerte (this.NomModèle);

2
SnktJavaMaster

J'ai eu le même problème.
La bonne façon serait de définir le 'searchText' pour qu'il soit une propriété à l'intérieur d'un objet.

Mais que se passe-t-il si je veux le laisser tel quel, une chaîne? Eh bien, j'ai essayé toutes les méthodes mentionnées ici, rien n'a fonctionné.
Mais ensuite, j'ai remarqué que le problème ne concernait que l'initiation, je viens donc de définir l'attribut value et cela a fonctionné.

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

De cette façon, la valeur est simplement définie sur la valeur '$ scope.searchText' et elle est mise à jour lorsque la valeur d'entrée change.

Je sais que c'est une solution de contournement, mais cela a fonctionné pour moi ..

2
Hike Nalbandyan