การปฏิบัติที่ดีที่สุดสำหรับการโทร AJAX ใน Angular.js คืออะไร


151

ฉันอ่านบทความนี้: http://eviltrout.com/2013/06/15/ember-vs-angular.html

และมันก็พูดว่า

เนื่องจากมันขาดการประชุมฉันสงสัยว่าโครงการ Angular หลายโครงการต้องอาศัยแนวปฏิบัติที่ไม่ดีเช่น AJAX โทรโดยตรงภายในคอนโทรลเลอร์? นักพัฒนากำลังฉีดพารามิเตอร์เราเตอร์ไปยังคำสั่งหรือไม่ ผู้พัฒนา AngularJS จะเริ่มวางโครงสร้างโค้ดในลักษณะที่นักพัฒนา AngularJS ที่มีประสบการณ์เชื่อว่าเป็นไปในทางที่ผิดหรือไม่?

จริงๆแล้วฉันกำลัง$httpโทรจากคอนโทรลเลอร์ Angular.js ของฉัน ทำไมมันถึงเป็นเรื่องไม่ดี วิธีที่ดีที่สุดสำหรับการ$httpโทรนั้นคืออะไร? และทำไม?


12
+1 สำหรับการอ้างอิงถึงโพสต์ที่น่าสนใจเปรียบเทียบถ่านและแองกูลาร์
Chandermani

ฉันสงสัยเหมือนกันเกี่ยวกับวิธีปฏิบัติที่ดีที่สุดเชิงมุม
Dalorzo

นอกจากนี้ยังตรวจสอบ API สำหรับสิ่งที่คุณอาจพลาด: docs.angularjs.org/api/ng/service/$http
Christophe Roussy

คำตอบ:


174

แก้ไข: คำตอบนี้มุ่งเน้นไปที่รุ่น 1.0.X เป็นหลัก เพื่อป้องกันความสับสนจะมีการเปลี่ยนแปลงเพื่อสะท้อนคำตอบที่ดีที่สุดสำหรับ Angular รุ่นปัจจุบันทั้งหมด ณ วันนี้ 2013-12-05

แนวคิดคือการสร้างบริการที่ส่งคืนสัญญาไปยังข้อมูลที่ส่งคืนจากนั้นเรียกใช้ในตัวควบคุมของคุณและจัดการสัญญาที่นั่นเพื่อเติมคุณสมบัติ $ scope

บริการ

module.factory('myService', function($http) {
   return {
        getFoos: function() {
             //return the promise directly.
             return $http.get('/foos')
                       .then(function(result) {
                            //resolve the promise as the data
                            return result.data;
                        });
        }
   }
});

ตัวควบคุม:

จัดการกับthen()วิธีการของสัญญาและนำข้อมูลออกมา ตั้งค่าคุณสมบัติ $ scope และทำสิ่งอื่นที่คุณอาจต้องทำ

module.controller('MyCtrl', function($scope, myService) {
    myService.getFoos().then(function(foos) {
        $scope.foos = foos;
    });
});

การแก้ปัญหาสัญญาในมุมมอง (1.0.X เท่านั้น):

ใน Angular 1.0.X เป้าหมายของคำตอบดั้งเดิมที่นี่สัญญาจะได้รับการดูแลเป็นพิเศษจากมุมมอง เมื่อพวกเขาแก้ไขค่าที่แก้ไขแล้วจะถูกผูกไว้กับมุมมอง สิ่งนี้เลิกใช้แล้วใน 1.2.X

module.controller('MyCtrl', function($scope, myService) {
    // now you can just call it and stick it in a $scope property.
    // it will update the view when it resolves.
    $scope.foos = myService.getFoos();
});

4
การพูดถึงจะใช้งานได้เฉพาะเมื่อคุณใช้$scope.foosคุณสมบัติในเทมเพลต หากคุณต้องใช้คุณสมบัติเดียวกันนั้นนอกเทมเพลต (ตัวอย่างเช่นในฟังก์ชันอื่น) วัตถุที่เก็บไว้ยังคงเป็นวัตถุสัญญา
Clark Pan

1
ขณะนี้ฉันกำลังใช้รูปแบบนี้ในแอพเชิงมุมใหม่ แต่ฉันสงสัยในหน้าหยาบวิธีการเข้าถึงคุณสมบัติที่ฉันผูกไว้กับขอบเขตในตัวอย่างนี้ถ้าฉันต้องการนำข้อมูลจาก getFoos และโพสต์การเปลี่ยนแปลงไปยัง มัน. ถ้าฉันลองและเข้าถึง $ scope.foos ในการอัปเดตของฉันฉันมีวัตถุสัญญาและไม่ใช่ข้อมูลฉันสามารถดูวิธีรับข้อมูลในวัตถุเอง แต่ดูเหมือนว่าแฮ็คจริงจริงๆ
Kelly Milligan

5
@ KellyMilligan ในรูปแบบนี้มันเป็นความผูกพันที่รู้ว่าจะทำอย่างไรกับสัญญา หากคุณจำเป็นต้องเข้าถึงวัตถุจากที่ใดก็ได้อื่นคุณกำลังจะมีการจัดการกับ.then()สัญญาและใส่ค่าใน $ ขอบเขต ...myService.getFoos().then(function(value) { $scope.foos = value; });
เบนเลช

1
เพียงแค่อัปเดตเกี่ยวกับเทคนิคนี้ตั้งแต่ 1.2.0-rc.3 การยกเลิกสัญญาโดยอัตโนมัติได้ถูกยกเลิกดังนั้นเทคนิคนี้จะไม่ทำงานอีกต่อไป
Clark Pan

2
มี downvotes สองสามที่นี่เมื่อเร็ว ๆ นี้น่าจะเป็นเพราะมันไม่สอดคล้องกับ Angular เวอร์ชันล่าสุดอีกต่อไป ฉันได้อัปเดตคำตอบเพื่อแสดงว่า
เบ็นเลช

45

แนวทางปฏิบัติที่ดีที่สุดคือการสรุปการ$httpโทรออกเป็น 'บริการ' ที่ให้ข้อมูลกับตัวควบคุมของคุณ:

module.factory('WidgetData', function($http){
    return {
        get : function(params){
            return $http.get('url/to/widget/data', {
                params : params
            });
        }
    }
});

module.controller('WidgetController', function(WidgetData){
    WidgetData.get({
        id : '0'
    }).then(function(response){
        //Do what you will with the data.
    })
});

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

คุณควรคิดว่า 'บริการ' เป็นตัวแทน (หรือรุ่น) ของข้อมูลที่แอปพลิเคชันของคุณสามารถใช้ได้


9

คำตอบที่ยอมรับคือทำให้ฉันมี$http is not definedข้อผิดพลาดดังนั้นฉันต้องทำสิ่งนี้:

var policyService = angular.module("PolicyService", []);
policyService.service('PolicyService', ['$http', function ($http) {
    return {
        foo: "bar",
        bar: function (params) {
            return $http.get('../Home/Policy_Read', {
                params: params
            });
        }
    };
}]);

ความแตกต่างที่สำคัญคือบรรทัดนี้:

policyService.service('PolicyService', ['$http', function ($http) {

1

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

https://stackoverflow.com/a/38958644/5349719

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