web-dev-qa-db-fra.com

Impossible d'obtenir la valeur textarea dans angularjs

Voici mon plnkr: http://plnkr.co/edit/n8cRXwIpHJw3jUpL8PX5?p=preview Vous devez cliquer sur un élément li et le formulaire apparaîtra. Entrez une chaîne aléatoire et cliquez sur 'ajouter un avis'. Au lieu du texte textarea, vous obtiendrez undefined.

Balisage:

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

Partie JS:

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

renvoie 'non défini'. J'ai remarqué que cela ne fonctionnait pas avec ui-if of angular-ui. Des idées pourquoi cela ne fonctionne pas? Comment le réparer?

50
Artjom Zabelin

Votre problème réside dans la partie ui-if. Angular-ui crée une nouvelle portée pour tout ce qui est contenu dans cette directive. Par conséquent, pour accéder à la portée parente, vous devez procéder comme suit:

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

Au lieu de

<textarea ng-model="noticeText"></textarea>
94
Mathew Berg

Ce problème m'est arrivé sans utiliser le ng-if directive sur les éléments entourant l'élément textarea. Bien que la solution de Mathew soit correcte, la raison semble en être une autre. La recherche de cette question pointe vers ce post, j'ai donc décidé de partager cela.

Si vous regardez la documentation AngularJS ici https://docs.angularjs.org/api/ng/directive/textarea , vous pouvez voir que Angular ajoute le sien directive appelée <textarea> qui "remplace" l'élément HTML textarea par défaut. C'est la nouvelle portée qui cause tout le gâchis.

Si vous avez une variable comme

$scope.myText = 'Dummy text';

dans votre contrôleur et liez-le à l'élément textarea comme ceci

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

AngularJS recherchera cette variable dans le champ d'application de la directive. Ce n'est pas là et donc il marche vers $ parent. La variable y est présente et le texte est inséré dans le textarea. Lorsque vous modifiez le texte dans textarea, Angular ne modifie PAS la variable du parent. Il crée à la place une nouvelle variable dans le champ d'application de la directive. Par conséquent, la variable d'origine n'est pas mise à jour. Si vous liez le textarea à la variable du parent, comme suggéré par Mathew, Angular sera toujours lié à la bonne variable et le problème aura disparu.

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

J'espère que cela éclaircira les choses pour les autres personnes qui abordent cette question et se disent: "WTF, je n'utilise pas ng-if ou toute autre directive dans mon cas!" comme je l'ai fait quand j'ai atterri pour la première fois ici;)

Update: utilise la syntaxe controller-as

Je voulais ajouter ça longtemps avant mais je n'ai pas trouvé le temps de le faire. C’est le style moderne des contrôleurs de bâtiments qui doit être utilisé à la place du $parent choses ci-dessus. Lisez la suite pour découvrir comment et pourquoi.

Depuis AngularJS 1.2, il est possible de référencer directement l’objet contrôleur au lieu d’utiliser le $scope objet. Ceci peut être réalisé en utilisant cette syntaxe dans le balisage HTML:

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

Les modules de routage populaires (c.-à-d. UI Router) fournissent des propriétés similaires pour leurs états. Pour le routeur d'interface utilisateur, vous utilisez les éléments suivants dans votre définition d'état:

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

Cela nous aide à contourner le problème lié aux étendues imbriquées ou mal adressées. L'exemple ci-dessus serait construit de cette façon. D'abord la partie JavaScript. Droit, vous simple ne pas utiliser le $scope référence pour définir votre texte, utilisez simplement this pour associer la propriété directement à l’objet contrôleur.

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

Le balisage pour le textarea avec la syntaxe controller-as ressemblerait à ceci:

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

C’est la manière la plus efficace de procéder de la sorte, car elle résout le problème des étendues imbriquées nous permettant de compter le nombre de couches que nous avons à un certain point. Utilisation de plusieurs directives imbriquées dans des éléments avec un ng-controller directive aurait pu conduire à quelque chose comme ceci en utilisant l'ancienne méthode de référencement des portées. Et personne ne veut vraiment faire ça toute la journée!

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

Liez la zone de texte à la variable propriété d'une variable de portée plutôt que directement à une variable de portée:

manette:

$scope.notice = {text: ""}

modèle:

<textarea ng-model="notice.text"></textarea>
26
Nimo

Il est en effet, ui-if qui crée le problème. Angular si les directives détruisent et recréent des parties de l’arborescence des doms en fonction de l’expression. C’est ce qui crée la nouvelle portée et non la directive textarea suggérée par marandus.

Voici un article sur les différences entre ngIf et ngShow qui décrit bien cela — quelle est la différence entre ng-if et ng-show/ng-hide .

2
Thomas O'Brien