Ng-model tidak memperbarui nilai pengontrol

270

Mungkin pertanyaan konyol, tapi saya punya formulir html dengan input dan tombol sederhana:

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

Kemudian di controller (template dan controller dipanggil dari routeProvider):

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

Mengapa saya melihat tampilan diperbarui dengan benar tetapi tidak terdefinisi di konsol saat mengklik tombol?

Terima kasih!

Pembaruan: Sepertinya saya telah benar-benar menyelesaikan masalah itu (sebelum harus menemukan beberapa solusi) dengan: Hanya perlu mengubah nama properti saya dari searchTextmenjadi search.text, kemudian menetapkan $scope.search = {};objek kosong di controller dan voila ... Tidak tahu mengapa ini bekerja meskipun;]

alkimia
sumber
Anda yakin menggunakan pengontrol ini di bagian dokumen ini? dapatkah Anda memposting contoh gagal minimal?
wroniasty
1
Ya, 100% yakin controllernya ok, masalah itu sepertinya sudah tidak asing lagi bagi saya ... Anehnya itu berfungsi ketika saya mengubah nama properti dari searchTextmenjadi search.text, tahu mengapa?
alkimia
4
@Arthur: Agak tidak jelas tetapi ng-model hanya menciptakan semacam variabel lokal berbicara dalam pandangan Anda, karena itu jika Anda ingin tetap seperti ini Anda harus meneruskannya ke fungsi check (), seperti: check ( searchText) dan pengontrol Anda akan mengenalinya kemudian. Semoga ini bisa membantu
alkimia
3
Sebagai catatan, itu dieja voila, tidak vuala, wolladll
Dan Bechard
3
Saya pikir jawaban yang Anda cari adalah di stackoverflow.com/a/14049482/1217913
Willa

Jawaban:

71

Kontroler sebagai versi (disarankan)

Di sini templatnya

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

Sebuah contoh: http://codepen.io/Damax/pen/rjawoO

Yang terbaik adalah menggunakan komponen dengan Angular 2.x atau Angular 1.5 atau lebih tinggi

#########

Cara lama (TIDAK disarankan)

Ini TIDAK direkomendasikan karena string adalah primitif, sangat disarankan untuk menggunakan objek

Coba ini di markup Anda

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

dan ini di controller Anda

$scope.check = function (searchText) {
    console.log(searchText);
}
Damax
sumber
17
Ini hanya bekerja satu arah ... bagaimana jika Anda ingin mengubah nilai searchText?
cdmckay
199
Ini juga tidak menjawab "mengapa?" pertanyaan.
cdmckay
4
bagaimana jika saya tidak ingin menggunakan tombol apa pun? saya perlu mengirimkan pada enter misalnya
danikoren
2
Saniko => Untuk mengirim saat masuk, Anda harus menggunakan tag formulir dan ng-kirim di atasnya ( docs.angularjs.org/api/ng.directive:ngSubmit )
Damax
1
@ HP's411 itu karena string adalah primitif. Ketika Angular menetapkan nilai itu mengubah pointer ke nilai, jadi controller melihat nilai lama karena memiliki pointer lama ke nilai.
Damax
620

"Jika kamu menggunakan ng-model, kamu harus memiliki titik di sana."
Buat model Anda menunjuk ke object.property dan Anda akan baik-baik saja.

Pengendali

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

Templat

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

Ini terjadi ketika cakupan anak sedang dimainkan - seperti rute anak atau ng-pengulangan. Lingkup anak membuat nilainya sendiri dan konflik nama lahir seperti diilustrasikan di sini :

Lihat klip video ini untuk lebih banyak: https://www.youtube.com/watch?v=SBwoFkRjZvE&t=3m15s

Will Stern
sumber
94
Inilah jawaban sebenarnya.
keslert
16
@ Kucing Dengan warisan prototipe, setiap kali Anda menulis ke properti anak, referensi / koneksi ke properti induk tidak ada lagi. Cara model Angular Scopes, jika Anda tidak memiliki titik, maka properti baru dalam lingkup anak Anda dibuat. Video ini menjelaskan lebih detail: youtube.com/watch?v=ZhfUv0spHCY&feature=youtu.be&t=30m
Will Stern
1
Gracias Boss. Ini benar! Namun, itu tampaknya tidak menjadi kekhasan yang konsisten karena saya menghadapi masalah hanya ketika menggunakan dengan kerangka kerja Ionic
Don Barry
6
@ user3677331 Ini berfungsi dengan baik tanpa titik sampai Anda memiliki ruang lingkup anak yang mencoba untuk berbicara dengannya (seperti item dalam ng-repeat misalnya). Katakanlah nama model Anda adalah "telepon" Lingkup anak Anda menciptakan "telepon", maka Anda mendapat konflik lingkup karena ruang lingkup anak memiliki variabel "telepon" dan dengan demikian tidak dapat mengakses "telepon" pada lingkup induk. Sedangkan jika lingkup anak membuat user.phone, itu akan ditambahkan ke objek pengguna induk sehingga kedua cakupan menunjuk ke objek yang sama
Will Stern
3
Sangat membantu. Saya tidak yakin akan menemukan jawaban untuk pertanyaan yang relatif samar tetapi ini sudah mati.
CodeManiak
57

Dalam Menguasai Pengembangan Aplikasi Web dengan AngularJS buku hal.19, tertulis bahwa

Hindari ikatan langsung ke properti lingkup. Mengikat data dua arah ke properti objek (diekspos pada lingkup) adalah pendekatan yang lebih disukai. Sebagai aturan praktis, Anda harus memiliki titik dalam ekspresi yang disediakan untuk arahan model-ng (misalnya, ng-model = "thing.name").

Lingkup hanyalah objek JavaScript, dan mereka meniru hierarki dom. Menurut JavaScript Prototype Inheritance , properti lingkup dipisahkan melalui cakupan. Untuk menghindari hal ini, notasi titik harus digunakan untuk mengikat model-ng.

efirat
sumber
2
terima kasih untuk referensi ini. Saya menganggap ini hal yang menarik terkait dengan ng-model.
Raja
44

Menggunakan thisalih-alih $scopebekerja.

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>

Sunting: Pada saat menulis jawaban ini, saya memiliki situasi yang jauh lebih rumit daripada ini. Setelah komentar, saya mencoba mereproduksi untuk memahami mengapa itu berhasil, tetapi tidak berhasil. Saya pikir entah bagaimana (tidak benar-benar tahu mengapa) lingkup anak baru dihasilkan dan thismengacu pada lingkup itu. Tetapi jika $scopedigunakan, itu sebenarnya merujuk ke parent $ scope karena lingkup leksikal javascript fitur .

Akan lebih bagus jika seseorang yang memiliki masalah ini menguji cara ini dan memberi tahu kami.

Feyyaz
sumber
Tanpa
1
Sepertinya fungsi yang dilampirkan untuk $scopemembuat ruang lingkup baru (yaitu dalam fungsi check(), thismerujuk ke ruang lingkup yang merupakan ruang lingkup anak $scope). Kenapa gitu? Bisakah Anda memberi penjelasan?
Xun Yang
1
mengapa saya harus menggunakan 'ini' daripada '$ lingkup' dalam kasus ini? karena ia bekerja menggunakan $ scope dalam proyek saya sebelumnya tetapi kali ini hal yang sama tidak bekerja menggunakan $ scope. Tapi 'ini' berhasil. Mengapa demikian?
Rashedul.Rubel
ini berfungsi, tetapi jika Anda mengatakan this.searchText = "something else"atau bahkan jika $scope.searchText = "something else", itu tidak memperbarui tampilan. dapatkah Anda menjelaskan masalah ini?
Shri
Itu harus. Saya mencobanya menggunakan kode di atas, itu memperbarui tampilan.
Feyyaz
13

Saya memiliki masalah yang sama dan itu karena saya tidak mendeklarasikan objek kosong terlebih dahulu di bagian atas controller saya:

$scope.model = {}

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

Semoga ini akan bekerja untuk Anda!

Millsionaire
sumber
10

Saya menemukan masalah yang sama ketika berhadapan dengan pandangan non-sepele (ada ruang bersarang). Dan akhirnya ditemukan bahwa ini adalah hal yang sulit diketahui ketika mengembangkan aplikasi AngularJS karena sifat dasar prototipe dari java-script. Lingkup bersarang AngularJS dibuat melalui mekanisme ini. Dan nilai yang dibuat dari ng-model ditempatkan di lingkup anak-anak, tidak mengatakan lingkup orang tua (mungkin yang disuntikkan ke controller) tidak akan melihat nilai, nilainya juga akan membayangi properti apa pun dengan nama yang sama yang didefinisikan dalam lingkup orang tua jika tidak menggunakan titik untuk menegakkan akses referensi prototipe. Untuk detail lebih lanjut, checkout video online khusus untuk menggambarkan masalah ini, http://egghead.io/video/angularjs-the-dot/ dan komentar yang menindaklanjutinya.

Roger Jin
sumber
6

Lihatlah biola ini http://jsfiddle.net/ganarajpr/MSjqL/

Saya (saya berasumsi!) Telah melakukan persis apa yang Anda lakukan dan tampaknya berhasil. Bisakah Anda memeriksa apa yang tidak berfungsi di sini untuk Anda?

Ganaraj
sumber
Hmmmm .. terima kasih telah melihat ini, saya akan menganggap itu harus bekerja ... mengapa tidak bekerja untuk saya Dan apa yang lebih penting: Mengapa ia bekerja dengan objek dan tidak dengan variabel string polos ?? Mungkin karena saya merujuk pengendali saya dengan cara yang tidak sesuai di routeProvider ?? Sedang mencoba untuk menghindari global dan telah menempatkan controller saya sebagai modulename.ctrlName ke file controllers.js. Bisakah itu menyebabkan sakit kepala?
alkimia
Saya tidak begitu yakin mengapa itu tidak berhasil untuk Anda. Jika Anda dapat mengisolasi masalah ini dalam biola, saya kira seseorang akan dapat memberi Anda jawaban yang lebih baik :)
ganaraj
Oke, akan lakukan, hanya menyelesaikan pekerjaan sekarang tetapi pasti akan melakukannya besok atau nanti malam, bersorak! Mungkin ada masalah dengan cara saya menamai ctrl saya, kita akan lihat ...
alkimia
6

Karena tidak ada yang menyebutkan ini, masalahnya dapat diselesaikan dengan menambahkan $parentke properti terikat

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

Dan pengontrolnya

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

    $scope.BankLogin = function () {
        console.log($scope.ssn); // works!
    };
}]);
Eric Herlitz
sumber
terima kasih atas jawabannya, namun apakah ini berfungsi? idealnya harus bekerja pada elemen ruang lingkup yang sama, bukan induknya?
V31
5

Bagi saya masalahnya diselesaikan dengan menyimpan data saya menjadi sebuah objek (di sini "data").

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

});

Saya berharap ini akan membantu

Plici Stéphane
sumber
3
Sedikit dari topik di sini, tetapi 'data' adalah istilah jamak untuk 'datum'
thethakuri
@thethakuri dan "datum" dalam bahasa Hungaria adalah "tanggal", jadi saya yakin tidak akan menggunakannya: P
EpicPandaForce
Saya lebih suka wafel rumah daripada IHOP
Nico Westerdale
2

Saya baru saja mengalami masalah ini menggunakan root_controller terikat ke elemen-tubuh. Kemudian saya menggunakan ng-view dengan router sudut. Masalahnya adalah SELALU sudut menciptakan ruang lingkup baru ketika menyisipkan html ke elemen ng-view. Sebagai konsekuensinya, fungsi "cek" saya didefinisikan pada lingkup induk dari lingkup yang dimodifikasi oleh elemen ng-model saya.

Untuk mengatasi masalah tersebut, gunakan saja pengontrol khusus di dalam konten html yang dimuat rute.

moritz
sumber
2

Anda dapat melakukannya untuk mengaktifkan pencarian di ng-keypressenter untuk input teks dan di ng-clickuntuk ikon:

<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);
        }
    }
Naoufal Gaffa
sumber
2

Saya memiliki masalah yang sama.
Cara yang tepat adalah mengatur 'searchText' menjadi properti di dalam objek.

Tetapi bagaimana jika saya ingin membiarkannya seperti itu, sebuah string? baik, saya mencoba setiap metode yang disebutkan di sini, tidak ada yang berhasil.
Tapi kemudian saya perhatikan bahwa masalahnya hanya di inisiasi, jadi saya baru saja menetapkan atribut nilai dan itu berhasil.

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

Dengan cara ini nilai hanya disetel ke nilai '$ scope.searchText' dan diperbarui ketika nilai input berubah.

Saya tahu ini solusinya, tapi itu berhasil untuk saya ..

Mendaki Nalbandyan
sumber
2

Saya menghadapi masalah yang sama ... Resolusi yang berhasil bagi saya adalah menggunakan kata kunci ini ..........

lansiran (this.ModelName);

SnktJavaMaster
sumber