Не удается получить значение textarea в angularjs

Вот мой plnkr: http://plnkr.co/edit/n8cRXwIpHJw3jUpL8PX5?p=preview Вы должны нажать на элементе li и появится форма. Введите случайную строку и нажмите «Добавить уведомление». Вместо текста текстовой области вы получите undefined.

Разметка:

<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);
}

возвращает «неопределенное». Я заметил, что это не работает при использовании ui-if из angular-ui. Любые идеи, почему это не работает? Как это исправить?


person Upvote    schedule 29.04.2013    source источник


Ответы (4)


Ваша проблема заключается в части ui-if. Angular-ui создает новую область для всего, что находится в этой директиве, поэтому для доступа к родительской области вы должны сделать что-то вроде этого:

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

Вместо

<textarea ng-model="noticeText"></textarea>
person Mathew Berg    schedule 29.04.2013
comment
Это работало нормально. Танк вас так много. Можете ли вы сказать, почему это происходит для textarea. - person Adarsh Singh; 19.11.2019

Эта проблема возникла у меня, когда я не использовал директиву ng-if для элементов, окружающих элемент textarea. Хотя решение Мэтью верно, причина, по-видимому, в другом. Поиск этой проблемы указывает на этот пост, поэтому я решил поделиться этим.

Если вы посмотрите документацию по AngularJS здесь https://docs.angularjs.org/api/ng/directive/textarea вы можете видеть, что Angular добавляет свою собственную директиву с именем <textarea>, которая «переопределяет» элемент HTML textarea по умолчанию. Это новая область, которая вызывает весь беспорядок.

Если у вас есть переменная типа

$scope.myText = 'Dummy text';

в вашем контроллере и привяжите его к элементу textarea следующим образом

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

AngularJS будет искать эту переменную в области действия директивы. Его там нет, и поэтому он идет к $parent. Переменная там присутствует и текст вставляется в файл textarea. При изменении текста в textarea Angular НЕ изменяет родительскую переменную. Вместо этого он создает новую переменную в области действия директивы, поэтому исходная переменная не обновляется. Если вы привяжете textarea к родительской переменной, как предложил Мэтью, Angular всегда будет привязываться к правильной переменной, и проблема исчезнет.

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

Надеюсь, это прояснит ситуацию для других людей, которые задают этот вопрос и думают: «WTF, я не использую ng-if или любую другую директиву в моем случае!» как я сделал, когда я впервые приземлился здесь;)

Обновление: используйте синтаксис контроллера как

Давно хотел добавить, но все не было времени. Это современный стиль построения контроллеров, и его следует использовать вместо $parent материала выше. Читайте дальше, чтобы узнать, как и почему.

Начиная с AngularJS 1.2 появилась возможность напрямую ссылаться на объект контроллера вместо использования объекта $scope. Этого можно добиться, используя следующий синтаксис в HTML-разметке:

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

Популярные модули маршрутизации (например, UI Router) предоставляют аналогичные свойства для своих состояний. Для UI Router вы используете следующее в своем определении состояния:

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

Это помогает нам обойти проблему с вложенными или неправильно адресованными областями. Приведенный выше пример будет построен таким образом. Сначала часть JavaScript. Прямо вперед, вы просто не используете ссылку $scope для установки вашего текста, просто используйте this для присоединения свойства непосредственно к объекту контроллера.

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

Разметка для textarea с синтаксисом controller-as будет выглядеть так:

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

На сегодняшний день это самый эффективный способ делать подобные вещи, потому что он решает проблему с вложенными областями видимости, заставляя нас считать, на скольких слоях мы находимся в определенный момент. Использование нескольких вложенных директив внутри элементов с директивой ng-controller могло привести к чему-то подобному при использовании старого способа ссылки на области видимости. И никто не хочет делать это весь день!

<textarea ng-model="$parent.$parent.$parent.$parent.myText"></textarea>
person marandus    schedule 20.11.2014
comment
Отличное подробное объяснение! Очень полезно! - person Wolfgang; 29.06.2015
comment
Спас мою жизнь. Спасибо за объяснение! - person NewestStackOverflowUser; 01.12.2015

Привяжите текстовое поле к свойству переменной области, а не непосредственно к переменной области:

контроллер:

$scope.notice = {text: ""}

шаблон:

<textarea ng-model="notice.text"></textarea>
person Nimo    schedule 25.10.2015
comment
Это сработало для меня в Angular 1.5. Странное ограничение, я почти уверен, что это работало (еще в 1.3?), привязанное непосредственно к переменной области видимости... - person robru; 01.03.2016
comment
Это решение кажется лучше, чем $parent.notice!! - person Paritosh; 13.03.2016
comment
Ваше решение сработало. Любое объяснение, почему прямая привязка не удалась? - person Shivendra; 11.05.2016
comment
Это решение сработало. Другое решение с $parent не сработало. - person Martin Staufcik; 08.09.2016
comment
Это лучшее решение - person Gogul; 30.09.2016

Действительно, ui-if создает проблему. Директивы Angular if уничтожают и воссоздают части дерева dom на основе выражения. Это создает новую область действия, а не директиву textarea, как предложил Марандус.

Вот сообщение о различиях между ngIf и ngShow, которое хорошо описывает это — в чем разница между ng-if и ng-show/ng-hide.

person Thomas O'Brien    schedule 13.04.2015