ฉันสามารถเข้าถึงแบบฟอร์มในคอนโทรลเลอร์ได้หรือไม่?


152

ฉันกำลังใช้สิ่งต่อไปนี้

$scope.$$childHead.customerForm[firstName], ดังนั้น:

<form name="customerForm">
  <input type="text" name="firstName" 
         ng-model="data.customer.firstName" 
         tabindex="1"  
         ng-disabled="!data.editable" 
         validationcustomer />
</form>

แต่ใช้งานได้เฉพาะใน Chrome ตอนนี้ฉันพยายามต่อไปนี้:

$scope.editCustomerForm[firstName], ดังนั้น:

<form name="customerForm" ng-model="editCustomerForm">
  <input type="text" name="firstName" 
         ng-model="data.customer.firstName" tabindex="1"  
         ng-disabled="!data.editable" 
         validationcustomer />
</form>

ซึ่งไม่ได้ผล หมายเหตุแบบฟอร์มของฉันอยู่ในแท็บพื้นฐาน ฉันจะเข้าถึงได้firstNameอย่างไร

แก้ไข : ดูเหมือนว่าformจะไม่ถูกเพิ่มเข้าไปscopeเมื่ออยู่ในแท็บรากฐาน

ใครมีวิธีแก้ปัญหานี้?

คำตอบ:


210

แม้ว่าจะมีการกล่าวถึงในความคิดเห็นอื่น ๆ ฉันคิดว่าฉันจะอธิบายออกมาเล็กน้อยสำหรับผู้ที่ใช้ไวยากรณ์ "Controller As":

<div ng-controller="MyController as ctrl">

<form name="ctrl.myForm">
    ...inputs
    Dirty? {{ctrl.myForm.$dirty}}

    <button ng-click="ctrl.saveChanges()">Save</button>
</form>

</div>

จากนั้นคุณสามารถเข้าถึง FormController ในรหัสของคุณเช่น:

function MyController () {
    var vm = this;
    vm.saveChanges = saveChanges;

    function saveChanges() {

       if(vm.myForm.$valid) { 
            // Save to db or whatever.
            vm.myForm.$setPristine();
       }
}

เท่าที่ฉันเห็นเทมเพลตไม่สามารถเรียกเมธอด "saveChanges" ได้เนื่องจากไม่ได้เปิดเผยเทมเพลต
Spock

2
วิธีการ "บันทึกการเปลี่ยนแปลง" จะปรากฏในบรรทัดที่ 3 ของจาวาสคริปต์หรือฉันเข้าใจผิด?
slopapa

3
นี้เป็นสิ่งที่ดีเพราะมันหมายความว่าคุณสามารถหลีกเลี่ยงการฉีดทั้ง $ ขอบเขตซึ่งเป็นสิ่งที่สะอาดในความคิดของฉัน
72GM

2
คุณทดสอบสิ่งนี้ในดอกมะลิอย่างไร ในสเป็คของฉัน vm.myForm ไม่ได้กำหนด
bahrieinn

1
ควรบันทึกไว้ในเอกสารอย่างเป็นทางการสำหรับ 1.5.X ซึ่งเป็นวิธีการทำส่วนประกอบและ es6 ขอบคุณครับ
MatanCo

91

คุณสามารถแนบแบบฟอร์มกับวัตถุบางอย่างที่กำหนดไว้ในตัวควบคุมหลัก จากนั้นคุณสามารถเข้าถึงแบบฟอร์มของคุณได้จากขอบเขตลูก

ตัวควบคุมหลัก

$scope.forms = {};

แม่แบบบางอย่างในขอบเขตลูก

<form name="forms.form1">
</form>

ปัญหาคือว่าไม่จำเป็นต้องกำหนดแบบฟอร์มในช่วงเวลาที่โค้ดในคอนโทรลเลอร์จะถูกดำเนินการ คุณต้องทำอะไรแบบนี้

$scope.$watch('forms.form1', function(form) {
  if(form) {
    // your code...
  }
});

10
ฉันขอแนะนำให้ใช้var watcher = $scope.$watcherและด้านในของข้อความ if ถ้าคุณจะ excute watcher () เพื่อยกเลิกการโยงนาฬิกา สิ่งนี้ทำให้ดูได้ 1 ครั้งดังนั้นคุณจะไม่ได้ดูทุกสรุปย่อยหลังจากที่ตั้งค่าไว้
willJk

91

หากคุณต้องการส่งแบบฟอร์มไปยังตัวควบคุมเพื่อจุดประสงค์ในการตรวจสอบความถูกต้องคุณสามารถส่งแบบฟอร์มนี้เป็นอาร์กิวเมนต์ไปยังวิธีการจัดการการส่ง ใช้ชื่อฟอร์มดังนั้นสำหรับคำถามดั้งเดิมมันจะเป็นสิ่งที่ต้องการ:

<button ng-click="submit(customerForm)">Save</button>

13
ชี้แจงสำหรับผู้อ่านในอนาคตถ้าพูดแบบฟอร์มของคุณเป็นชื่อ / ที่กำหนดไว้ที่คล้ายกันนี้<form name="myform"></form>หรือแม้กระทั่งจากนั้นเหตุการณ์คลิกของคุณจะเป็นดังนี้<div ng-form name="myform"></div> ng-click="submit(myform)"จากนั้นคุณสามารถเข้าถึงวัตถุรูปแบบเชิงมุมในการทำงานคลิกของคุณที่ชอบ: $scope.submit = function (form) { if (form.$valid) {ฯลฯ
แมทตี้ J

ฉันพบปัญหาที่นี่ - สมมติว่ามีรายการแบบเลื่อนลงในแบบฟอร์ม การใช้วิธีการด้านบนทำให้ฉันมีเพียงค่ามุมมองและไม่ใช่ค่าที่แน่นอนที่ฉันต้องการ หรือฉันกำลังทำอะไรผิดจะเพิ่มซอ
swateek

82

สายเกินไปสำหรับคำตอบ แต่มาพร้อมกับตัวเลือกต่อไปนี้ มันใช้งานได้สำหรับฉัน แต่ไม่แน่ใจว่าเป็นวิธีที่ถูกต้องหรือไม่

ในมุมมองของฉันฉันกำลังทำสิ่งนี้:

<form name="formName">
    <div ng-init="setForm(formName);"></div>
</form>

และในตัวควบคุม:

$scope.setForm = function (form) {
    $scope.myForm = form;
}

ตอนนี้หลังจากทำสิ่งนี้ฉันได้รับแบบฟอร์มของฉันในตัวแปรคอนโทรลเลอร์ซึ่งก็คือ $scope.myForm


1
สิ่งเดียวที่ฉันเพิ่มในนี้คือการตรวจสอบให้แน่ใจว่านี่อยู่ที่ด้านล่างของแบบฟอร์ม
smb

ตำแหน่งของ <div ng-init = "setForm (formName);"> </div> ไม่สำคัญ เพียงระวังให้อยู่ในรูปแบบ
waqas

1
ดี แต่ฉันต้องการโซลูชันที่เรียบง่ายกว่า: ng-init = "$ parent.myForm = formName" โดยไม่จำเป็นต้องเปลี่ยนคอนโทรลเลอร์หมายเหตุ: มันใช้งานได้เฉพาะกับคอนโทรลเลอร์โดยตรงเท่านั้นซึ่งตรงกันข้ามกับโซลูชันด้านบน
mastilver

หลังจากลองใช้วิธีอื่นฉันก็ตัดสินเรื่องนี้เพราะมันทำให้nameคุณสมบัตินั้นเป็นอย่างที่ฉันต้องการ ปัญหากับการแก้ปัญหาวัตถุจำลองอื่น ๆ คือถ้าใช้องค์ประกอบนี้ในส่วนประกอบอื่นที่มีรูปแบบ ng รูปแบบ ng อื่น ๆ ที่ใช้ชื่อแบบฟอร์มนี้อย่างแท้จริง ดังนั้นมันจะมีฟิลด์ที่มีชื่อสตริง (ไม่ใช่คุณสมบัติที่ซ้อนกัน) ของตัวอักษร "dummy.myForm" ฉันพบสิ่งนี้ที่ยอมรับไม่ได้
เพรา

ฉันพยายามและล้มเหลวหลายครั้งในการใช้ไวยากรณ์ controllerAs (ฉันทำงานกับ $ mdDialog) ในที่สุดก็ตัดสินเรื่องนี้และมันก็ทำได้ดีมาก สิ่งที่ควรทราบก็คือการเริ่มต้นคอนโทรลเลอร์ใด ๆ จำเป็นต้องเรียกใช้ในการหมดเวลา $ เนื่องจากรูปแบบไม่พร้อมใช้งานเมื่อคอนโทรลเลอร์ทำงานครั้งแรก
Peter

22

เพื่อให้สามารถเข้าถึงแบบฟอร์มในตัวควบคุมของคุณคุณจะต้องเพิ่มลงในวัตถุขอบเขตจำลอง

สิ่งที่ต้องการ $scope.dummy = {}

สำหรับสถานการณ์ของคุณสิ่งนี้จะมีความหมายเช่น:

<form name="dummy.customerForm">

ในตัวควบคุมของคุณคุณจะสามารถเข้าถึงแบบฟอร์มโดย:

$scope.dummy.customerForm

และคุณจะสามารถทำสิ่งต่าง ๆ เช่น

$scope.dummy.customerForm.$setPristine()

ลิงค์ WIKI

มี '.' ในแบบจำลองของคุณจะทำให้มั่นใจได้ว่ามรดกต้นแบบนั้นกำลังเล่นอยู่ ดังนั้นใช้<input type="text" ng-model="someObj.prop1">มากกว่า<input type="text" ng-model="prop1">

หากคุณต้องการ / จำเป็นต้องใช้แบบดั้งเดิมมีวิธีแก้ไขสองวิธี:

1.Use $ parent.parentScopeProperty ในขอบเขตลูก สิ่งนี้จะป้องกันขอบเขตลูกไม่ให้สร้างคุณสมบัติของตนเอง 2. กำหนดฟังก์ชันบนขอบเขตพาเรนต์และเรียกใช้จาก child ผ่านค่าดั้งเดิมไปจนถึง parent (ไม่สามารถทำได้)


พื้นที่ที่มีประสิทธิภาพในการกำหนดรูปแบบผูกพันอยู่ที่ไหน
Gus Crawford

มันเป็นมูลค่าการกล่าวขวัญว่าdummy.customerFormจะไม่ได้กำหนดจนกว่าng-ifจะได้พบกับเงื่อนไขขององค์ประกอบแบบฟอร์มที่มีng-ifเงื่อนไขตามที่มัน
haxxxton

22

คำตอบนี้มาสายนิดหน่อย แต่ฉันสะดุดกับวิธีแก้ปัญหาที่ทำให้ทุกอย่างง่ายขึ้นมาก

คุณสามารถกำหนดชื่อฟอร์มให้กับคอนโทรลเลอร์ของคุณได้โดยตรงหากคุณใช้ไวยากรณ์ controllerAs แล้วอ้างอิงจากตัวแปร "this" ของคุณ นี่คือวิธีที่ฉันทำในรหัสของฉัน:

ฉันกำหนดค่าคอนโทรลเลอร์ผ่าน ui-router (แต่คุณสามารถทำได้ตามที่คุณต้องการแม้จะอยู่ใน HTML โดยตรงกับสิ่งอื่น ๆ<div ng-controller="someController as myCtrl">) นี่คือสิ่งที่มันอาจดูเหมือนในการกำหนดค่า ui-router:

views: {
            "": {
                templateUrl: "someTemplate.html",
                controller: "someController",
                controllerAs: "myCtrl"
            }
       }

จากนั้นใน HTML คุณเพียงตั้งชื่อฟอร์มเป็น "controllerAs" "ชื่อ" เป็นดังนี้:

<ng-form name="myCtrl.someForm">
    <!-- example form code here -->
    <input name="firstName" ng-model="myCtrl.user.firstName" required>
</ng-form>

ในตอนนี้คุณสามารถทำสิ่งนี้ได้ภายในคอนโทรลเลอร์ของคุณ:

angular
.module("something")
.controller("someController",
    [
       "$scope",
        function ($scope) {
            var vm = this;
            if(vm.someForm.$valid){
              // do something
            }
    }]);

2
แม้ว่านี่จะเป็นเทคนิคเดียวกับคำตอบอื่น ๆ ที่แนะนำส่วนใหญ่ แต่เป็นรูปแบบที่ดีที่สุดและควรเป็นคำตอบที่ยอมรับโดยเฉพาะอย่างยิ่งเนื่องจากทุกคนใช้คอนโทรลเลอร์เป็นตอนนี้
เซมิโคลอน

6

ใช่คุณสามารถเข้าถึงแบบฟอร์มในตัวควบคุม (ตามที่ระบุไว้ในเอกสาร )

ยกเว้นเมื่อไม่ได้กำหนดฟอร์มของคุณในขอบเขตควบคุมและกำหนดไว้ในขอบเขตลูกแทน

โดยทั่วไปบางสั่งเชิงมุมเช่นng-if, ng-repeatหรือng-includeจะสร้างขอบเขตเด็กโดดเดี่ยว คำสั่งที่กำหนดเองใด ๆ ดังนั้นจะมีscope: {}คุณสมบัติที่กำหนดไว้ อาจเป็นไปได้ว่าองค์ประกอบพื้นฐานของคุณอยู่ในทางของคุณ

ฉันมีปัญหาเดียวกันเมื่อแนะนำง่ายๆng-ifรอบ ๆ<form>แท็ก

ดูเหล่านี้สำหรับข้อมูลเพิ่มเติม:

หมายเหตุ:ฉันแนะนำให้คุณเขียนคำถามอีกครั้ง คำตอบสำหรับคำถามของคุณคือใช่แต่ปัญหาของคุณแตกต่างกันเล็กน้อย:

ฉันสามารถเข้าถึงแบบฟอร์มในขอบเขตลูกจากตัวควบคุมได้หรือไม่

ซึ่งคำตอบที่ได้ก็จะเป็น: ไม่มี


... ถ้าคุณตั้งค่ารูปแบบและการควบคุมของคุณตามที่อธิบายไว้ในคำตอบ @ondrs' (ใช้$scope.forms = {}และname="forms.form1")
marapet

โปรดดูคำตอบข้างบนของคุณทันทีโดย KhalilRavanna คุณสามารถเข้าถึงแบบฟอร์มจาก $ scope.formName เขาแสดงตัวอย่างการทำงาน
micahblu

3

เพิ่มng-model="$ctrl.formName"คุณสมบัติให้กับฟอร์มของคุณและจากนั้นในตัวควบคุมคุณสามารถเข้าถึงแบบฟอร์มเป็นวัตถุภายในตัวควบคุมของคุณโดยthis.formName


0

คุณไม่สามารถเข้าถึงแบบฟอร์มในขอบเขตได้แน่นอน มันไม่ได้ถูกสร้างขึ้น DOM จากเทมเพลต html ถูกโหลดอย่างช้าๆเหมือนกับตัวสร้างคอนโทรลเลอร์ การแก้ปัญหาคือการดูจนกว่าจะโหลด DOM และขอบเขตทั้งหมดที่กำหนดไว้!

ในตัวควบคุม:

$timeout(function(){
    console.log('customerForm:', $scope.customerForm);
    // everything else what you need
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.