การส่งผ่านขอบเขตปัจจุบันไปยังบริการ AngularJS


106

การส่ง "กระแส" $scopeไปยังบริการ AngularJS ถูกต้องหรือไม่

ฉันอยู่ในสถานการณ์ที่ฉันใช้บริการ $ โดยรู้ว่ามันถูกใช้โดยคอนโทรลเลอร์เพียงตัวเดียวและฉันต้องการอ้างอิงถึงขอบเขตของคอนโทรลเลอร์ในวิธีการบริการของ $ เอง

นี่ถูกต้องตามหลักปรัชญาหรือไม่?

หรือฉันจะดีกว่าที่จะถ่ายทอดกิจกรรมไปยัง $ rootScope แล้วทำให้คอนโทรลเลอร์ของฉันฟังมัน


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

ก็ไม่ยากเท่าไหร่ ฉันต้องการเข้าถึง$scopeคุณสมบัติและโทรหา$scope.$applyเมื่อจำเป็น
SC

นอกจากนี้บอกว่าฉันต้องการใช้การเปลี่ยนแปลงที่มาจาก $ service กับ $ scope หวังว่าตอนนี้จะชัดเจนขึ้น
SC

8
ฉันขอแนะนำให้คุณใส่คุณสมบัติ $ ขอบเขตที่คุณต้องการให้บริการของคุณเข้าถึงในบริการนั้นเอง (แทนที่จะให้มันอยู่ในตัวควบคุม) บริการเป็นสถานที่จัดเก็บโมเดล / ข้อมูลที่ดีกว่าตัวควบคุม
Mark Rajcok

@MarkRajcock ฉันพยายามเข้าใจปัญหานี้เช่นกัน ขณะนี้ฉันกำลังเรียกใช้บริการและแนบข้อมูลที่ให้บริการกับคอนโทรลเลอร์$scope... คอนโทรลเลอร์จะเข้าถึงข้อมูลในบริการโดยตรงและส่งต่อไปยังมุมมองโดยไม่ทำสิ่งนี้ได้อย่างไร
drjimmie1976

คำตอบ:


67

เพื่อให้การควบคุมรู้ว่าสิ่งที่เกิดขึ้น async ใช้สัญญาเชิงมุม

ในการกระตุ้น$applyคุณไม่จำเป็นต้องมีขอบเขตคุณสามารถโทร$rootScope.$applyได้เนื่องจากไม่มีความแตกต่างในการเรียกมันในขอบเขตเฉพาะหรือในรูท

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


ฉันคิดว่านี่เป็นคำตอบที่ช่วยแก้ข้อสงสัยสำหรับมือใหม่ AngularJS ของฉันได้ดีขึ้น
SC

@Caio Cunha คุณช่วยขยายความได้ไหมว่าทำไมจึงไม่ควรผ่านขอบเขต? ฉันมีปัญหาตรงนี้ฉันต้องการเพิ่มบางอย่าง$scopeผ่านการโทรไปยังบริการโดยใช้executeSql()ฟังก์ชันasync ดูใน 3 ตัวเลือก (1) ใช้การโทรกลับบนฟังก์ชัน async แล้วเรียก$scope.$apply... สิ่งนี้ใช้งานได้ แต่น่าเกลียด (2) ส่งผ่าน$scopeไปยังฟังก์ชัน async จากนั้นเรียกtheScope.$apply()... สิ่งนี้ใช้ได้เช่นกัน (3) ใช้คำสัญญา .. ยังไม่ได้ลองทำ ทำไมคำสัญญาจึงเป็นวิธีที่ดีที่สุด? ขอบคุณ!
drjimmie1976

15

ฉันจะบอกว่าฟังก์ชันการทำงานของคุณเฉพาะสำหรับคอนโทรลเลอร์เพียงตัวเดียวเท่านั้นที่คุณไม่ต้องการบริการ

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

นี่คือสิ่งที่เอกสารกล่าว

บริการ

บริการเชิงมุมคือเสื้อกล้ามที่ทำหน้าที่เฉพาะที่ใช้กันทั่วไปในเว็บแอป

ตัวควบคุม

ใน Angular คอนโทรลเลอร์คือฟังก์ชัน JavaScript (ประเภท / คลาส) ที่ใช้เพื่อเพิ่มอินสแตนซ์ของขอบเขตเชิงมุมโดยไม่รวมขอบเขตรูท

PS: นอกเหนือจากนั้นหากคุณต้องการแยกย่อยคุณยังสามารถฉีด $ rootScope ภายในบริการของคุณ


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

อย่างไรก็ตามการชี้แจงเกี่ยวกับการโทร$applyหรือ$digest$ rootScope นั้นสมเหตุสมผลสำหรับฉัน
SC

1
ฉันยังคงแยกไว้เป็นบริการสำหรับการทดสอบ
bluehallu

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

9

ใช่. คุณสามารถส่งผ่าน $ ขอบเขตไปยังบริการได้เมื่อคุณเริ่มต้น ในตัวสร้างบริการคุณสามารถกำหนดขอบเขตให้กับสิ่งนี้ได้ _scope แล้วอ้างอิงขอบเขตภายในบริการ!

angular.module('blah').controller('BlahCtrl', function($scope, BlahService) {

    $scope.someVar = 4;

    $scope.blahService = new blahService($scope);

});

angular.module('blah').factory('blahService', function() {

    //constructor
    function blahService(scope) {
        this._scope = scope;

        this._someFunction()
    }

    //wherever you'd reference the scope
    blahService.prototype._someFunction = function() {

        this._scope['someVar'] = 5;

    }

    return blahService;

});

1
+1 แต่ผมอยากจะเห็นวิธีที่จะรู้โดยอัตโนมัติแต่ละตัวควบคุมของ$scopeเมื่อใดก็ตามที่ได้รับอัดฉีดควบคุมบริการ - เพื่อให้เป็นไปไม่ได้ที่จะเรียกวิธีการในการให้บริการด้วยตนเองผ่าน$scopeไป
Cody

2
@Cody ฉันไม่แนะนำว่ามันขัดแย้งกับ Dependency Injection
Coldstar

ตกลง +1 สำหรับการยิงฉัน! อาจเป็นไปได้ว่า Butchers DIP - ฉันจะบอกว่ามีความเสี่ยงที่จะซ้ำซ้อน
Cody

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

@Karvapallo จุดดี. ในฐานะที่เป็นจุดนับฉันเชื่อว่าบริการเชิงมุมหมายถึงโรงงานบริการและผู้ให้บริการ (ng-wat)?
user12121234

6

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

นอกเหนือจากความสับสนในแง่ของความสัมพันธ์แล้วสิ่งเช่นนี้ก็กลายเป็นการขัดขวางคนเก็บขยะ

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

ตัวอย่างเช่นหากบริการควรจะพุชและป๊อปองค์ประกอบจากอาร์เรย์errorsรหัสของฉันจะเป็น:

var errors = [];
$scope.errors = errors;
$scope.myService = new MyService(errors);

errorsโต้ตอบบริการแล้วกับตัวควบคุมโดยการดำเนินงานใน แน่นอนฉันต้องระมัดระวังที่จะไม่ลบการอ้างอิงอาร์เรย์ทั้งหมด แต่ในตอนท้ายของวันนั้นเป็นปัญหาทั่วไปของ JS

ฉันไม่ต้องการใช้การแพร่ภาพ$applyและ / หรือสิ่งที่คล้ายกันเพราะการปฏิบัติ OO ที่ดีของ imho มักจะเหนือกว่าสิ่งใดก็ตามที่เป็น Angular-magics


1
รหัสนี้มีความแตกต่างกับรหัสนี้หรือไม่:$scope.errors = []; $scope.myService = new MyService($scope.errors);
Soldeplata Saketos

@SoldeplataSaketos - ใช่ค่ะ มีชีวิตอยู่อย่างอิสระerrors $scopeนั่นคือจุดรวมของคำตอบนี้ โปรดตรวจสอบลิงค์ที่ฉันให้ไว้ในข้อความ ไชโย
Marco Faustinelli

1
หากฉันเข้าใจรหัสของคุณถูกต้องมีการ$scope.errorsชี้ไปvar errorsและข้อผิดพลาดของตัวแปรดูเหมือนซ้ำซ้อนสำหรับฉันเนื่องจากเป็นเพียงตัวชี้อื่น const errors = errors2 = errors3 = []; $scope.errors = errors;หนึ่งในสถานการณ์ที่คล้ายกันที่ฉันสามารถคิดและว่ามันเป็นอย่างโจ๋งครึ่มซ้ำซ้อนเป็นชิ้นส่วนของรหัสนี้: คุณยอมรับว่ามีเพียงส่วนของรหัสที่คุณให้มาดูเหมือนว่าvar errors = []ซ้ำซ้อน?
Soldeplata Saketos

ไม่มันไม่ใช่. ฉันทำซ้ำตัวเองโดยคำ: มีชีวิตอยู่อย่างอิสระerrors $scopeคุณต้องเข้าใจว่าออบเจ็กต์โดเมนคืออะไรและvarงานคืออะไร หากลิงก์ที่ฉันให้ไว้ไม่เพียงพอมีข้อมูลอื่น ๆ อีกมากมาย
Marco Faustinelli

นั่นจะขึ้นอยู่กับการใช้งานฟังก์ชันMyService(errors)เท่านั้น ตามความเข้าใจของฉันบริการควรสร้างอาร์เรย์การบันทึกตามพารามิเตอร์ (ซึ่งในกรณีนี้คือตัวชี้) สำหรับฉันนั่นเป็นรูปแบบที่ไม่ดีเนื่องจากบริการเป็นแบบซิงเกิลในเชิงมุม หากการใช้งานบริการได้รับการตั้งโปรแกรมไว้อย่างดีก็ควรสร้างอาร์เรย์ในตัวแปรภายใน (เพื่อให้เป็นซิงเกิลตัน) ดังนั้นจึงไม่มีเหตุผลที่จะเริ่มต้นตัวแปรภายนอกบริการ
Soldeplata Saketos
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.