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


270

Можливо, дурне запитання, але у мене є форма HTML з простим введенням і кнопкою:

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

Потім у контролері (шаблон і контролер викликаються з routeProvider):

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

Чому я бачу подання оновлене правильно, але невизначене в консолі, коли натискаєте кнопку?

Дякую!

Оновлення: Схоже, я фактично вирішив цю проблему (раніше довелося придумати деякі обхідні шляхи) з: Тільки треба було змінити моє ім'я власності з searchTextна search.text, потім визначити порожній $scope.search = {};об’єкт у контролері та вуаля ... Не маю поняття, чому це працює хоч;]


Ви впевнені, що використовуєте цей контролер у цій частині документа? чи можете ви розмістити мінімальний невдалий приклад?
wroniasty

1
Так, на 100% впевнений, що з контролером все в порядку, ця проблема здається мені знайомою ... Дивно, але це працює, коли я змінюю ім'я властивості з searchTextна search.text, будь-яка ідея чому ??
алхімікація

4
@Arthur: Це щось не очевидно, але ng-модель створює лише своєрідну локальну змінну розмовляння на вашому погляді, тому, якщо ви хочете зберегти її таким чином, вам потрібно буде передати її у функцію check (), наприклад: check ( searchText) і ваш контролер розпізнає його тоді. Сподіваюся, що це допомагає
алхімікація

3
Для запису, це пишеться voila, а НЕ vuala, wollaі т.д.
Dan Bechard

3
Я думаю, що відповідь, яку ви шукаєте, є на stackoverflow.com/a/14049482/1217913
Willa,

Відповіді:


71

Контролер як версія (рекомендується)

Ось шаблон

<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

Найкраще буде використовувати компонент з кутовим 2.x або кутовим 1.5 або верхнім

########

Старий спосіб (НЕ рекомендується)

Це НЕ рекомендується, оскільки рядок є примітивним, настійно рекомендується замість цього використовувати об'єкт

Спробуйте це у своїй розмітці

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

і це у вашому контролері

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

17
Це працює лише в одну сторону ... що робити, якщо ви хочете змінити значення searchText?
cdmckay

199
Це також не відповідає "чому?" питання.
cdmckay

4
що робити, якщо я не хочу використовувати жодну кнопку? Мені потрібно представити, наприклад,
enter

2
Saniko => Щоб подати на введення, ви повинні використовувати тег форми та ng-submit на ньому ( docs.angularjs.org/api/ng.directive:ngSubmit )
Damax

1
@ HP's411 це тому, що рядок є примітивом. Коли Angular присвоює значення, він змінює вказівник на значення, тому контролер дивиться на старе значення, оскільки у нього є старий вказівник на значення.
Дамакс

620

"Якщо ви використовуєте 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-повтори. Дочірнє поле створює власну цінність і народжується конфлікт імен, як показано тут : Більше

див. У цьому відеокліпі: https://www.youtube.com/watch?v=SBwoFkRjZvE&t=3m15s


94
Це справжня відповідь.
keslert

16
@Catfish З прототиповим успадкуванням кожного разу, коли ви пишете до дочірньої властивості, посилання / з'єднання з батьківською властивістю припиняє своє існування. Те, як модель Angular Scopes моделює, якщо у вас немає крапки, створюється нове властивість у межах вашої дитини. Це відео пояснює це більш докладно: youtube.com/watch?v=ZhfUv0spHCY&feature=youtu.be&t=30m
Will Stern

1
Gracias Boss. Це правда! Однак це, здається, не є послідовною вигадкою, оскільки я стикаюся з проблемою лише під час використання з Ionic Framework
Дон Баррі

6
@ user3677331 Це прекрасно спрацьовує без крапки, поки у вас не з’явиться дочірня область, яка намагається поговорити з нею (наприклад, із предметом у ng-повторі, наприклад). Скажіть, що назва вашої моделі "телефон". Ваша дочірня область створює "телефон", тоді ви отримуєте конфлікт сфери, оскільки дочірнє поле має змінну "телефон" і, отже, не може отримати доступ до "телефону" на батьківській області. Якщо, якщо дочірнє поле створює user.phone, він буде доданий до об'єкта користувача батьків, тож обидві області вказують на один і той же об’єкт
Буде Стерн

3
Дуже корисний. Я не був впевнений, що знайду відповідь на відносно розпливчасте питання, але це було мертвим.
CodeManiak

57

У Освоєнні розробки веб-додатків з книгою AngularJS с.19 написано, що

Уникайте прямих прив’язок до властивостей області. Двосторонній зв'язок даних щодо властивостей об'єкта (викритий на області дії) є кращим підходом. Як правило, ви повинні мати крапку у виразі, наданому директиві ng-model (наприклад, ng-model = "thing.name").

Області застосування - це лише об’єкти JavaScript, і вони імітують ієрархію дому. Відповідно до наслідування прототипу JavaScript , властивості областей розділяються через області застосування. Щоб уникнути цього, позначення крапок слід використовувати для прив’язки ng-моделей.


2
дякую за це посилання. Я вважаю це цікавим моментом, пов’язаним з ng-моделлю.
Королі

44

Використання 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 .

Було б чудово, якби хтось із цією проблемою перевірив цей спосіб і повідомив нам про це.


Бездоганний, ти геній
fjcero

1
Схоже, що функції, приєднані до $scopeстворення, створюють нову область (тобто у функції check(), thisстосується області, яка є дочірньою областю $scope). Чому так? Чи можете ви дати пояснення?
Сюн Ян

1
чому я повинен використовувати "це" замість "$ range" в цьому випадку? тому що він працював, використовуючи $ range в моєму попередньому проекті, але цього разу те ж саме не працює, використовуючи $ range. Але "це" спрацювало. Чому так?
Рашедул.Рубель

це працює, але якщо ви скажете this.searchText = "something else"чи навіть навіть $scope.searchText = "something else", він не оновлює подання. чи можете ви пояснити цю проблему?
Шрі

воно повинно. Я спробував це за допомогою наведеного вище коду, оновив подання.
Фейяз

13

У мене була така ж проблема, і це було через те, що я не оголошував спочатку пустий об'єкт у верхній частині мого контролера:

$scope.model = {}

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

Сподіваємось, це допоможе вам!


10

Я зіткнувся з тим же питанням, коли розглядав нетривіальний погляд (є вкладені сфери застосування). І нарешті виявив, що це відома хитра річ при розробці програми AngularJS завдяки природі успадкування Java-скрипту на основі прототипу. За допомогою цього механізму створюються вкладені сфери AngularJS. І значення, створене з ng-моделі, розміщується в області дітей, не кажучи, що батьківська область (можливо, та, яка введена в контролер), не побачить значення, значення також затінить будь-яке властивість з тим самим іменем, визначеним у батьківській області, якщо не використовувати крапку для забезпечення доступу до прототипу по прототипу. Щоб отримати докладніші відомості, перегляньте онлайн-відео, яке конкретно проілюструє цю проблему, http://egghead.io/video/angularjs-the-dot/ та коментарі до неї.


6

Погляньте на цю скрипку http://jsfiddle.net/ganarajpr/MSjqL/

Я (я припускаю!) Зробив саме те, що ви робили, і, здається, працює. Чи можете ви перевірити, що тут не працює для вас?


Хмммм .. спасибі за те, що я вивчив це, я б припустив, що це має працювати ... чому це не працює для мене? І що важливіше: чому він працює з об'єктами, а не з простими рядковими змінними ?? Можливо, тому, що я спрямовую свої контролери неналежним чином у routeProvider ?? Намагався уникнути глобалістів і помістив мої контролери як modulename.ctrlName у файл controllers.js. Чи може це викликати головний біль?
алхімікація

Я не дуже впевнений, чому це не працює для вас. Якщо ви зможете відокремити це питання у загадці, я думаю, хтось зможе дати вам кращу відповідь :)
ganaraj

Гаразд, зроби, тільки закінчую роботу зараз, але зробимо це точно завтра чи пізно ввечері, ура! Можливо, буде проблема з тим, як я змінив імена моїх Ctrl, ми побачимо ...
alchemication

6

Оскільки про це ніхто не згадував, проблему можна вирішити, додавши $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!
    };
}]);

дякую за відповідь, проте у цього це працює? ідеально слід працювати над одним і тим же елементом сфери застосування, а не з батьківським?
V31

5

Для мене проблему було вирішено шляхом зберігання моїх даних в об’єкт (тут "дані").

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
Тут мало теми, але "дані" є множинним терміном для "дата"
thethakuri

@thethakuri і "дата" на угорській мові - це "дата", тому я точно не використовую це: P
EpicPandaForce

Я віддаю перевагу вафельному будинку IHOP
Ніко Вестердейл

2

У мене саме ця проблема була за допомогою root_controller, прив'язаного до елемента body. Тоді я використовував ng-view з кутовим маршрутизатором. Проблема полягає в тому, що кутова ЗАВЖДИ створює нову область, коли вона вставляє html в елемент ng-view. Як наслідок, моя функція "перевірка" була визначена в батьківській області області, яка була змінена моїм елементом ng-model.

Щоб вирішити проблему, просто використовуйте спеціальний контролер у вмісті завантаженого маршрутом html.


2

Ви можете зробити це, щоб увімкнути пошук ng-keypressвведення тексту для введення тексту та 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);
        }
    }

2

У мене була така ж проблема.
Правильним способом було б встановлення "searchText" для властивості всередині об'єкта.

Але що робити, якщо я хочу залишити його таким, яким він є, рядок? добре, я перепробував кожен згаданий тут метод, нічого не вийшло.
Але потім я помітив, що проблема полягає лише в ініціації, тому я просто встановив атрибут значення і він спрацював.

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

Таким чином, значення просто встановлюється на значення "$ range.searchText" і оновляється, коли значення введення змінюється.

Я знаю, що це рішення, але це спрацювало для мене ..


2

Я зіткнувся з тією ж проблемою ... Резолюція, яка працювала для мене, - це використовувати це ключове слово ..........

попередження (це. МодельName);

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.