รุ่น 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 = {};วัตถุว่างในคอนโทรลเลอร์และ voila ... ไม่รู้เลยว่าทำไมมันถึงใช้งานได้ แม้ว่า;]


คุณแน่ใจหรือว่าคุณใช้คอนโทรลเลอร์นี้ในส่วนนี้ของเอกสาร? คุณสามารถโพสต์ตัวอย่างความล้มเหลวน้อยที่สุดได้ไหม
wroniasty

1
ใช่ 100% แน่ใจว่าคอนโทรลเลอร์นั้นโอเคปัญหานั้นดูเหมือนจะคุ้นเคยกับฉัน ... น่าแปลกใจที่มันทำงานเมื่อฉันเปลี่ยนชื่อคุณสมบัติจากsearchTextเป็นเป็นsearch.textความคิดใด ๆ ว่าทำไม ??
เล่นแร่แปรธาตุ

4
@Arthur: มันไม่ชัดเจน แต่ ng-model สร้างการเรียงลำดับของการพูดตัวแปรท้องถิ่นในมุมมองของคุณมีก่อนถ้าคุณต้องการที่จะให้มันด้วยวิธีนี้คุณจะต้องผ่านมันเข้าไปในฟังก์ชั่นตรวจสอบ () เช่น: check ( searchText) แล้วคอนโทรลเลอร์ของคุณจะจดจำมันได้ หวังว่ามันจะช่วย
เล่นแร่แปรธาตุ

3
สำหรับบันทึกก็สะกดvoilaไม่vuala, wollaฯลฯ
แดน 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

วิธีที่ดีที่สุดคือใช้ส่วนประกอบที่มี 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);
}

17
วิธีนี้ใช้ได้เพียงทางเดียว ... จะเกิดอะไรขึ้นถ้าคุณต้องการเปลี่ยนค่าของsearchText?
cdmckay

199
สิ่งนี้ยังไม่ตอบ "ทำไม" คำถาม.
cdmckay

4
ถ้าฉันไม่ต้องการใช้ปุ่มใด ๆ ฉันจำเป็นต้องส่งที่ป้อนเช่น
danikoren

2
Saniko => หากต้องการส่งเมื่อป้อนคุณต้องใช้แบบฟอร์มแท็กและ ng-submit กับมัน ( docs.angularjs.org/api/ng.directive:ngSubmit )
Damax

1
@ HP's411 เป็นเพราะสตริงนั้นเป็นแบบดั้งเดิม เมื่อ Angular กำหนดค่ามันจะเปลี่ยนตัวชี้เป็นค่าดังนั้นคอนโทรลเลอร์จะดูค่าเก่าเนื่องจากมีตัวชี้เก่าเป็นค่า
Damax

620

"ถ้าคุณใช้โมเดล ng คุณจะต้องมีจุดอยู่ในนั้น"
ทำให้แบบจำลองของคุณชี้ไปที่วัตถุคุณสมบัติแล้วคุณก็พร้อมที่จะไป

ตัวควบคุม

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

แบบ

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

สิ่งนี้จะเกิดขึ้นเมื่อขอบเขตของเด็กกำลังเล่น - เช่นเส้นทางเด็กหรือเล่นซ้ำ ขอบเขตของลูกสร้างคุณค่าของตัวเองและความขัดแย้งของชื่อเกิดขึ้นตามที่แสดงไว้ที่นี่ :

ดูวิดีโอคลิปนี้เพิ่มเติม: https://www.youtube.com/watch?v=SBwoFkRjZvE&t=3m15s


94
นี่คือคำตอบที่แท้จริง
keslert

16
@ แคทฟิชด้วยการรับมรดกต้นแบบเมื่อใดก็ตามที่คุณเขียนไปยังคุณสมบัติของเด็กการอ้างอิง / การเชื่อมต่อกับคุณสมบัติของผู้ปกครองจะสิ้นสุดลง โมเดลของ Angular Scopes หากคุณไม่มีจุดดังนั้นคุณสมบัติใหม่ภายในขอบเขตลูกของคุณจะถูกสร้างขึ้น วิดีโอนี้อธิบายรายละเอียดเพิ่มเติมได้ที่: youtube.com/watch?v=ZhfUv0spHCY&feature=youtu.be&t=30m
Will Stern

1
กราเซียสบอส นี่เป็นเรื่องจริง! แต่ก็ไม่ได้ดูเหมือนจะเป็นมุมแหลมที่สอดคล้องกันเท่าที่ผมพบปัญหาที่เกิดขึ้นเฉพาะเมื่อใช้กับกรอบอิออน
ดอนแบร์รี่

6
@ user3677331 ใช้งานได้ดีโดยไม่มีจุดจนกว่าคุณจะมีขอบเขตลูกที่พยายามพูดคุยกับมัน (เช่นรายการที่อยู่ใน ng-repeat เป็นต้น) สมมติว่าชื่อรุ่นของคุณคือ "โทรศัพท์" ขอบเขตลูกของคุณสร้าง "โทรศัพท์" จากนั้นคุณจะได้รับขอบเขตที่ขัดแย้งกันเนื่องจากขอบเขตเด็กมีตัวแปร "โทรศัพท์" และไม่สามารถเข้าถึง "โทรศัพท์" ในขอบเขตหลักได้ โดยที่ถ้าขอบเขตลูกสร้าง user.phone มันจะถูกเพิ่มไปยังวัตถุผู้ใช้ของผู้ปกครองเพื่อให้ขอบเขตทั้งสองชี้ไปยังวัตถุเดียวกัน
Will Stern

3
มีประโยชน์มาก ฉันไม่แน่ใจว่าฉันจะหาคำตอบสำหรับคำถามที่ค่อนข้างคลุมเครือ แต่สิ่งนี้ตายไปแล้ว
CodeManiak

57

ในการพัฒนาเว็บแอพพลิเคชั่นที่มีหนังสือ AngularJS หน้า 19 มีการเขียนไว้ว่า

หลีกเลี่ยงการเชื่อมโยงโดยตรงกับคุณสมบัติของขอบเขต การผูกข้อมูลแบบสองทางกับคุณสมบัติของวัตถุ (เปิดเผยในขอบเขต) เป็นวิธีการที่แนะนำ ตามกฎของหัวแม่มือคุณควรมีจุดในนิพจน์ที่กำหนดให้กับคำสั่ง ng-model (ตัวอย่างเช่น ng-model = "thing.name")

ขอบเขตเป็นเพียงวัตถุ JavaScript และพวกเขาเลียนแบบลำดับชั้น dom ตามการสืบทอด JavaScript Prototypeคุณสมบัติขอบเขตจะถูกแยกผ่านขอบเขต เพื่อหลีกเลี่ยงปัญหานี้เครื่องหมายจุดควรใช้เพื่อผูก ng-models


2
ขอบคุณสำหรับการอ้างอิงนี้ ฉันคิดว่านี่เป็นประเด็นที่น่าสนใจเกี่ยวกับ ng-model
กษัตริย์

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ใช้แล้วจะหมายถึง parent $ scope เนื่องจากคุณสมบัติขอบเขตคำศัพท์ของ javascript

คงจะดีมากถ้ามีคนที่มีปัญหานี้ทดสอบวิธีนี้และแจ้งให้เราทราบ


ไร้ที่ติคุณเป็นอัจฉริยะ
fjcero

1
ดูเหมือนว่าฟังก์ชั่นที่แนบมากับ$scopeสร้างขอบเขตใหม่ (เช่นในการทำงานcheck(), thisหมายถึงขอบเขตที่เป็นขอบเขตของเด็ก$scope) ทำไมถึงเป็นเช่นนั้น? คุณช่วยอธิบายหน่อยได้ไหม?
Xun Yang

1
เหตุใดฉันจึงควรใช้ 'นี้' แทน '$ scope' ในกรณีนี้ เพราะมันทำงานโดยใช้ $ scope ในโครงการก่อนหน้าของฉัน แต่คราวนี้สิ่งเดียวกันไม่ทำงานโดยใช้ $ scope แต่ 'นี่' ได้ผลแล้ว ทำไมถึงเป็นอย่างนั้น?
Rashedul.Rubel

ใช้งานได้ แต่ถ้าคุณพูดthis.searchText = "something else"หรือแม้ว่า$scope.searchText = "something else"มันจะไม่ปรับปรุงมุมมอง คุณอธิบายปัญหานี้ได้ไหม
Shri

มันควรจะ. ฉันลองใช้รหัสข้างบนมันอัพเดตมุมมอง
Feyyaz

13

ฉันมีปัญหาเดียวกันและเป็นเพราะฉันไม่ได้ประกาศวัตถุเปล่าก่อนที่ด้านบนของตัวควบคุมของฉัน:

$scope.model = {}

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

หวังว่าสิ่งนี้จะได้ผลสำหรับคุณ!


10

ฉันเจอปัญหาเดียวกันเมื่อจัดการกับมุมมองที่ไม่สำคัญ (มีขอบเขตซ้อนกัน) และในที่สุดก็ค้นพบว่านี่เป็นสิ่งที่ยุ่งยากเมื่อรู้ว่าการพัฒนาแอปพลิเคชั่น AngularJS เนื่องจากลักษณะของการสืบทอดตามต้นแบบของจาวาสคริปต์ ขอบเขตที่ซ้อนกัน AngularJS ถูกสร้างผ่านกลไกนี้ และค่าที่สร้างขึ้นจาก ng-model จะอยู่ในขอบเขตของลูกไม่ใช่การบอกขอบเขตของแม่ (อาจจะเป็นอันที่ฉีดเข้าไปในคอนโทรลเลอร์) จะไม่เห็นค่าเลยค่านั้นจะเป็นเงาของคุณสมบัติใด ๆ เพื่อบังคับใช้การเข้าถึงการอ้างอิงต้นแบบ สำหรับรายละเอียดเพิ่มเติมให้ชำระเงินวิดีโอออนไลน์เฉพาะเพื่อแสดงให้เห็นถึงปัญหานี้http://egghead.io/video/angularjs-the-dot/และความคิดเห็นที่ตามมา


6

ดูซอนี้http://jsfiddle.net/ganarajpr/MSjqL/

ฉันมี (ฉันคิดว่า!) ทำสิ่งที่คุณทำและดูเหมือนว่าจะทำงาน คุณช่วยตรวจสอบสิ่งที่ไม่ทำงานที่นี่สำหรับคุณได้ไหม


อืมมมมมมมมมมมมมมมมมมมมมมม .. ด้วยล่ะขอบคุณที่พิจารณาสิ่งนี้ฉันคิดว่ามันน่าจะใช้ได้ ... ทำไมมันไม่เหมาะกับฉัน และมีความสำคัญมากกว่า: ทำไมมันทำงานกับวัตถุและไม่ได้มีตัวแปรสตริงธรรมดา? อาจทำให้ฉันอ้างถึงตัวควบคุมของฉันในวิธีที่เหมาะสมใน routeProvider พยายามหลีกเลี่ยง globals และทำให้ตัวควบคุมของฉันเป็น modulename.ctrlName ลงในไฟล์ controllers.js นั่นอาจทำให้ปวดหัว?
เล่นแร่แปรธาตุ

ฉันไม่แน่ใจจริงๆว่าทำไมมันถึงไม่เหมาะกับคุณ หากคุณสามารถแยกปัญหานี้ในซอผมคิดว่าคนที่จะสามารถที่จะให้คำตอบที่ดีกว่า :)
ganaraj

โอเคจะทำแค่เสร็จงานตอนนี้ แต่จะทำอย่างนั้นในวันพรุ่งนี้หรือหลังจากนั้นในตอนเย็นไชโย! อาจจะมีปัญหากับวิธีที่ผมเคย namespaced 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!
    };
}]);

ขอบคุณสำหรับคำตอบ y นี้ทำงานอย่างไร มันควรจะทำงานในองค์ประกอบขอบเขตขวาถูกต้องและไม่ได้เป็นผู้ปกครอง?
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
หัวข้อเล็กน้อยที่นี่ แต่ 'data' เป็นคำพหูพจน์สำหรับ 'datum'
thethakuri

@thethakuri และ "datum" ในภาษาฮังการีคือ "date" ดังนั้นฉันแน่ใจว่าจะไม่ใช้สิ่งนั้น: P
EpicPandaForce

ฉันชอบบ้านวาฟเฟิลกับ IHOP
Nico Westerdale

2

ฉันเพิ่งมีปัญหานี้โดยใช้ root_controller ที่ผูกไว้กับองค์ประกอบของร่างกาย จากนั้นฉันใช้มุมมอง ng กับเราเตอร์เชิงมุม ปัญหาคือว่าเชิงมุมเสมอสร้างขอบเขตใหม่เมื่อมันแทรก html ลงในองค์ประกอบมุมมอง ng เป็นผลให้ฟังก์ชั่น "ตรวจสอบ" ของฉันถูกกำหนดไว้ในขอบเขตหลักของขอบเขตที่ถูกแก้ไขโดยองค์ประกอบ 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}} />

วิธีนี้ค่าถูกตั้งค่าเป็น '$ scope.searchText' และจะถูกอัปเดตเมื่อมีการเปลี่ยนแปลงค่าอินพุต

ฉันรู้ว่ามันเป็นวิธีการแก้ปัญหา แต่มันได้ผลสำหรับฉัน ..


2

ฉันประสบปัญหาเดียวกัน ... การแก้ปัญหาที่ใช้งานได้สำหรับฉันคือการใช้คำหลักนี้ ..........

การแจ้งเตือน (this.ModelName);

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.