การกรองแบบสองทางใน AngularJS ทำอย่างไร?


124

สิ่งที่น่าสนใจอย่างหนึ่งที่ AngularJS สามารถทำได้คือใช้ตัวกรองกับนิพจน์การเชื่อมโยงฐานข้อมูลซึ่งเป็นวิธีที่สะดวกในการนำไปใช้เช่นสกุลเงินเฉพาะวัฒนธรรมหรือการจัดรูปแบบวันที่ของคุณสมบัติของโมเดล นอกจากนี้ยังดีที่มีคุณสมบัติที่คำนวณในขอบเขต ปัญหาคือคุณลักษณะเหล่านี้ไม่ทำงานกับสถานการณ์จำลองการเชื่อมต่อฐานข้อมูลแบบสองทาง - การเชื่อมฐานข้อมูลทางเดียวจากขอบเขตไปยังมุมมอง นี่ดูเหมือนจะเป็นการมองข้ามไปอย่างชัดเจนในห้องสมุดที่ยอดเยี่ยมอย่างอื่นหรือฉันพลาดอะไรไป?

ในKnockoutJSฉันสามารถสร้างคุณสมบัติที่คำนวณด้วยการอ่าน / เขียนซึ่งอนุญาตให้ฉันระบุคู่ของฟังก์ชันซึ่งเรียกว่าเพื่อรับค่าของคุณสมบัติและอีกฟังก์ชันหนึ่งที่ถูกเรียกเมื่อตั้งค่าคุณสมบัติ สิ่งนี้ทำให้ฉันสามารถใช้ตัวอย่างเช่นอินพุตที่รับรู้วัฒนธรรมโดยให้ผู้ใช้พิมพ์ "$ 1.24" และแยกวิเคราะห์เป็นลอยใน ViewModel และมีการเปลี่ยนแปลงใน ViewModel ที่แสดงในอินพุต

สิ่งที่ใกล้เคียงที่สุดที่ฉันสามารถพบได้คือการใช้$scope.$watch(propertyName, functionOrNGExpression);สิ่งนี้ช่วยให้ฉันมีฟังก์ชันที่เรียกใช้เมื่อคุณสมบัติในไฟล์$scopeเปลี่ยนแปลง แต่สิ่งนี้ไม่สามารถแก้ปัญหาได้เช่นปัญหาการป้อนข้อมูลที่คำนึงถึงวัฒนธรรม สังเกตเห็นปัญหาเมื่อฉันพยายามแก้ไข$watchedคุณสมบัติภายใน$watchวิธีการ:

$scope.$watch("property", function (newValue, oldValue) {
    $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
    $scope.property = Globalize.parseFloat(newValue);
});

( http://jsfiddle.net/gyZH8/2/ )

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

$scope.visibleProperty= 0.0;
$scope.hiddenProperty = 0.0;
$scope.$watch("visibleProperty", function (newValue, oldValue) {
    $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
    $scope.hiddenProperty = Globalize.parseFloat(newValue);
});

( http://jsfiddle.net/XkPNv/1/ )

นี่เป็นการปรับปรุงในเวอร์ชันแรก แต่มีรายละเอียดมากกว่าเล็กน้อยและสังเกตว่ายังมีปัญหาของไฟล์ parsedValueคุณสมบัติของการเปลี่ยนแปลงขอบเขต (พิมพ์บางสิ่งในอินพุตที่สองซึ่งเปลี่ยนแปลงparsedValueโดยตรงโปรดสังเกตว่าอินพุตด้านบนไม่ การปรับปรุง) สิ่งนี้อาจเกิดขึ้นจากการทำงานของตัวควบคุมหรือจากการโหลดข้อมูลจากบริการข้อมูล

มีวิธีที่ง่ายกว่าในการนำสถานการณ์นี้ไปใช้โดยใช้ AngularJS หรือไม่? ฉันไม่มีฟังก์ชันบางอย่างในเอกสารประกอบใช่หรือไม่

คำตอบ:


231

ปรากฎว่ามีวิธีแก้ปัญหาที่สวยงามมาก แต่ก็ไม่ได้รับการบันทึกไว้เป็นอย่างดี

การจัดรูปแบบค่าโมเดลสำหรับการแสดงผลสามารถจัดการได้โดยตัว|ดำเนินการและเชิงมุมformatterผู้ประกอบการและเชิงมุมปรากฎว่า ngModel ที่ไม่เพียง แต่มีรายการฟอร์แมตเท่านั้น แต่ยังมีรายการตัวแยกวิเคราะห์ด้วย

1. ใช้ng-modelเพื่อสร้างการผูกข้อมูลสองทาง

<input type="text" ng-model="foo.bar"></input>

2. สร้างคำสั่งในโมดูลเชิงมุมของคุณซึ่งจะนำไปใช้กับองค์ประกอบเดียวกันและขึ้นอยู่กับngModelตัวควบคุม

module.directive('lowercase', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attr, ngModel) {
            ...
        }
    };
});

3. ภายในlinkวิธีการนี้ให้เพิ่มตัวแปลงที่กำหนดเองของคุณลงในngModelคอนโทรลเลอร์

function fromUser(text) {
    return (text || '').toUpperCase();
}

function toUser(text) {
    return (text || '').toLowerCase();
}
ngModel.$parsers.push(fromUser);
ngModel.$formatters.push(toUser);

4. เพิ่มคำสั่งใหม่ของคุณไปยังองค์ประกอบเดียวกันกับที่มีไฟล์ ngModel

<input type="text" lowercase ng-model="foo.bar"></input>

นี่คือตัวอย่างการทำงานที่แปลงข้อความเป็นตัวพิมพ์เล็กในinputและกลับเป็นตัวพิมพ์ใหญ่ในโมเดล

เอกสาร API สำหรับรุ่นควบคุมนอกจากนี้ยังมีคำอธิบายสั้น ๆ และภาพรวมของวิธีการที่ใช้ได้อื่น ๆ


มีเหตุผลใดบ้างที่คุณใช้ "ngModel" เป็นชื่อสำหรับพารามิเตอร์ที่สี่ในฟังก์ชันการเชื่อมโยงของคุณ นั่นไม่ใช่แค่คอนโทรลเลอร์ทั่วไปสำหรับคำสั่งที่ไม่มีส่วนเกี่ยวข้องกับแอ็ตทริบิวต์ ngModel? (ยังคงเรียนรู้เชิงมุมอยู่ที่นี่ดังนั้นฉันอาจจะผิดทั้งหมด)
Drew Miller

7
เพราะ "ต้อง: 'ngModel" พารามิเตอร์ที่ 4 ฟังก์ชั่นการเชื่อมโยงจะเป็นผู้ควบคุมสั่ง ngModel ของ - คือควบคุม foo.bar ซึ่งเป็นตัวอย่างของngModelController คุณสามารถตั้งชื่อพารามิเตอร์ที่ 4 ได้ตามต้องการ (ฉันจะตั้งชื่อngModelCtrlนี้)
Mark Rajcok

8
เทคนิคนี้มีการบันทึกไว้ที่docs.angularjs.org/guide/formsในส่วน Custom Validation
Nikhil Dabas

1
@Mark Rajcok ในซอที่ให้มาขณะที่คลิกโหลดข้อมูล - ตัวพิมพ์เล็กทั้งหมดฉันคาดว่าค่าโมเดลจะอยู่ในตัวพิมพ์ใหญ่ทั้งหมด แต่ค่าโมเดลมีค่าน้อย คุณช่วยได้ไหม อธิบายว่าทำไมและวิธีการสร้างแบบจำลองเสมอใน CAPS
Rajkamal Subramanian

1
@rajkamal เนื่องจาก loadData2 () แก้ไข$scopeโดยตรงนั่นคือสิ่งที่โมเดลจะถูกตั้งค่าเป็น ... จนกว่าผู้ใช้จะโต้ตอบกับกล่องข้อความ เมื่อถึงจุดนั้นตัววิเคราะห์ใด ๆ ก็สามารถส่งผลต่อค่าโมเดลได้ นอกจากตัวแยกวิเคราะห์แล้วคุณสามารถเพิ่ม $ watch ให้กับคอนโทรลเลอร์ของคุณเพื่อแปลงค่าโมเดลได้
Mark Rajcok
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.