Ng-модель не обновляет значение контроллера

236

Возможно, глупый вопрос, но у меня есть html-форма с простым вводом и кнопкой:

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

Затем в контроллере (шаблон и контроллер вызывается из routeProvider):

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

Почему я вижу, что представление обновлено правильно, но undefined в консоли при нажатии кнопки?

Спасибо!

Обновление: Похоже, что я действительно решил эту проблему (раньше приходилось придумывать некоторые обходные пути): Мне нужно было изменить имя моего свойства от searchText до search.text, а затем определить пустой объект $scope.search = {}; в контроллере и voila... Не знаю, почему он работает, хотя;]

  • 0
    Вы уверены, что используете этот контроллер в этой части документа? Можете ли вы опубликовать минимальный неудачный пример?
  • 1
    Да, на 100% уверен, что с контроллером все в порядке, эта проблема мне знакома ... Удивительно, но это работает, когда я изменяю имя свойства с searchText на search.text , есть идеи почему ??
Показать ещё 6 комментариев
Теги:
data-binding
angular-ngmodel

12 ответов

57
Лучший ответ

Контроллер в качестве версии (рекомендуется)

Здесь шаблон

<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);
}
  • 0
    Спасибо!! Это прекрасно (а также решение многих проблем, которые у меня были в прошлом)! +1;)
  • 15
    Это работает только в одну сторону ... что делать, если вы хотите изменить значение searchText ?
Показать ещё 10 комментариев
542

"Если вы используете ng-модель, у вас должна быть точка".
Сделайте свою модель точкой 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-повторы. Массив child создает его собственную ценность, и возникает конфликт имен как показано здесь:

Смотрите этот видеоклип для получения дополнительной информации: https://www.youtube.com/watch?v=SBwoFkRjZvE&t=3m15s

  • 89
    Это настоящий ответ.
  • 0
    Это сработало для меня, но не могли бы вы уточнить «эту причуду» в javascript?
Показать ещё 15 комментариев
54

При освоении разработки веб-приложений с помощью книги AngularJS стр .19 написано, что

Избегайте прямых привязок к свойствам области. Двусторонняя привязка данных к свойства объекта (выставлены в области) являются предпочтительным подходом. Как эмпирическое правило, вы должны иметь точку в выражении, предоставленном ng-model (например, ng-model = "thing.name" ).

Области - это просто объекты JavaScript, и они имитируют иерархию dom. Согласно Наследование прототипа JavaScript, свойства областей разделяются по областям. Чтобы избежать этого, обозначение точки должно использовать для привязки ng-моделей.

  • 2
    спасибо за эту ссылку. Я считаю это интересным моментом, связанным с ng-моделью.
37

Работает 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 лексической области.

Было бы здорово, если кто-то, у кого эта проблема, проверит этот способ и сообщит нам.

  • 0
    Безупречен, ты гений
  • 1
    Похоже, функции, прикрепленные к $scope создают новую область (то есть в функции check() , this относится к области, которая является дочерней областью $scope ). Почему это так? Можете ли вы дать некоторые объяснения?
Показать ещё 3 комментария
10

У меня была та же проблема, и из-за этого я не объявлял пустой объект в верхней части моего контроллера:

$scope.model = {}

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

Надеюсь, это сработает для вас!

  • 0
    Пожалуйста!
9

Я столкнулся с одной проблемой при работе с нетривиальным представлением (есть вложенные области). И, наконец, обнаружил, что это известная сложная вещь при разработке приложения AngularJS из-за характера наследования на основе прототипа java- script. Благодаря этому механизму создаются вложенные области AngularJS. И значение, созданное из ng-модели, помещается в область child, не говоря о родительской области (возможно, тот, который вводится в контроллер) не увидит значение, значение также будет теневое свойство с тем же именем, которое определено в родительской области, если не использовать точку для обеспечения доступа к прототипу ссылок. Для получения дополнительной информации просмотрите онлайн-видео, чтобы проиллюстрировать эту проблему, http://egghead.io/video/angularjs-the-dot/ и комментарии, отслеживающие ее.

5

Посмотрите на эту скрипту http://jsfiddle.net/ganarajpr/MSjqL/

Я (я полагаю!) сделал то, что вы делали, и, похоже, работает. Можете ли вы проверить, что здесь не работает?

  • 0
    Хмммм .. спасибо, что заглянул в это, я бы предположил, что это должно работать ... почему это не работает для меня? И что более важно: почему он работает с объектами, а не с простыми строковыми переменными ?? Может быть потому, что я соответствующим образом направляю свои контроллеры в routeProvider ?? Пытался избежать глобалов и поместил мои контроллеры как modulename.ctrlName в файл controllers.js. Может ли это вызвать головную боль?
  • 0
    Я не совсем уверен, почему это не работает для вас. Если бы вы могли выделить эту проблему на скрипке, думаю, кто-то сможет дать вам лучший ответ :)
Показать ещё 1 комментарий
4

Для меня проблема была решена путем хранения моих данных в объект (здесь "данные" ).

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
    Немного не по теме здесь, но «данные» - это множественное число для термина «данные»
  • 0
    @thethakuri и «datum» на венгерском языке - это «дата», так что я уверен, что тоже не буду использовать это: P
Показать ещё 1 комментарий
1

Поскольку никто не упоминал об этом, проблему можно решить, добавив $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!
    };
}]);
  • 0
    спасибо за ответ, однако у это работает? в идеале он должен работать на том же элементе видимости, а не на родительском элементе?
0

У меня была та же проблема.
Правильным способом было бы установить "searchText" как свойство внутри объекта.

Но что, если я хочу оставить его как есть, строку? хорошо, я пробовал каждый из упомянутых здесь методов, ничего не работало.
Но потом я заметил, что проблема только в инициации, поэтому я только что установил атрибут value и работал.

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

Таким образом, значение просто устанавливается в значение $scope.searchText и оно обновляется при изменении входного значения.

Я знаю, что это обходное решение, но это сработало для меня.

0

Вы можете сделать это, чтобы включить поиск в ng-keypress enter для ввода текста и в 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);
        }
    }
0

У меня просто была эта проблема с использованием root_controller, связанного с элементом body. Затем я использовал ng-view с маршрутизатором angular. Проблема в том, что angular ALWAYS создает новую область, когда она вставляет html в элемент ng-view. Как следствие, моя функция "check" была определена в родительской области области действия, которая была изменена моим элементом ng-model.

Чтобы решить эту проблему, просто используйте выделенный контроллер в загруженном по маршруту html-содержимом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню