ฉันสามารถทำให้ฟังก์ชั่นนั้นมีอยู่ในคอนโทรลเลอร์ทุกตัวในเชิงมุมได้หรือไม่


191

ถ้าฉันมีฟังก์ชั่นยูทิลิตี้fooที่ฉันต้องการที่จะสามารถโทรจากที่ใดก็ได้ภายในng-appประกาศของฉัน มีบางอย่างที่ฉันสามารถทำให้สามารถเข้าถึงได้ทั่วโลกในการตั้งค่าโมดูลของฉันหรือฉันจำเป็นต้องเพิ่มมันเข้าไปในขอบเขตในทุก ๆ คอนโทรลเลอร์?


ฉันไม่แน่ใจ 100% เกี่ยวกับสิ่งนี้ แต่มีโอกาสที่คุณจะสามารถกำหนดมันในโมดูลของคุณเช่นนี้: module.value('myFunc', function(a){return a;});จากนั้นฉีดชื่อลงในคอนโทรลเลอร์ของคุณ (หากใครต้องการหลีกเลี่ยงการให้บริการ)
user2173353

หมายความว่าฉันต้องเพิ่มมันลงในคอนโทรลเลอร์ทุกตัวด้วยตนเอง $ rootScope เป็นวิธีที่จะไปสำหรับสิ่งที่ฉันต้องการจะทำเกือบ 2 ปีที่ผ่านมา =)
ลุดวิก Magnusson

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

คำตอบ:


290

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

<!doctype html>
<html ng-app="myApp">
<head>
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
    <script type="text/javascript">
    var myApp = angular.module('myApp', []);

    myApp.factory('myService', function() {
        return {
            foo: function() {
                alert("I'm foo!");
            }
        };
    });

    myApp.controller('MainCtrl', ['$scope', 'myService', function($scope, myService) {
        $scope.callFoo = function() {
            myService.foo();
        }
    }]);
    </script>
</head>
<body ng-controller="MainCtrl">
    <button ng-click="callFoo()">Call foo</button>
</body>
</html>

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

<!doctype html>
<html ng-app="myApp">
<head>
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
    <script type="text/javascript">
    var myApp = angular.module('myApp', []);

    myApp.run(function($rootScope) {
        $rootScope.globalFoo = function() {
            alert("I'm global foo!");
        };
    });

    myApp.controller('MainCtrl', ['$scope', function($scope){

    }]);
    </script>
</head>
<body ng-controller="MainCtrl">
    <button ng-click="globalFoo()">Call global foo</button>
</body>
</html>

ด้วยวิธีนี้แม่แบบทั้งหมดของคุณสามารถโทรได้globalFoo()โดยไม่ต้องผ่านมันไปยังแม่แบบจากตัวควบคุม


5
ในโซลูชันแรกจะเกิดอะไรขึ้นถ้ามีfoo()ฟังก์ชันมากมาย การทำ$scope.callFoo()เสื้อคลุมสำหรับทุกคนนั้นเป็นงานที่มากเกินไป ฉันจะ"แนบ"ฟังก์ชั่นทั้งหมดของห้องสมุดในขอบเขตเพื่อให้สามารถใช้ในแม่แบบได้อย่างไร ฉันมีไลบรารีการแปลงหน่วยขนาดใหญ่ที่ฉันต้องการให้มีอยู่ในเทมเพลตของฉัน
AlexStack

3
คำถามของฉันเช่นกัน ฉันลองมันแล้วมันใช้งานได้: คุณสามารถ "แนบ" มันได้โดยพูด$scope.callFoo = myService.foo;แทนการสร้าง wrapper ใหม่ในแต่ละที่ที่คุณต้องการใช้
ผู้ชายช่างฟิต

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

ฉันขอแนะนำให้ใช้ค่าเชิงมุมแทนที่จะเป็น Factory สำหรับกรณีเฉพาะนี้เว้นแต่คุณวางแผนที่จะมีฟังก์ชั่นหลายอย่างภายในบริการ หากเป็นเพียงฟังก์ชันเดียวให้ใช้เป็นค่า
Nicholas Blasgen

ฉันได้รับข้อผิดพลาด: [$ injector: unpr]
Mark Thien

53

คุณสามารถรวมเข้าด้วยกันฉันเดาว่า:

<!doctype html>
<html ng-app="myApp">
<head>
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
    <script type="text/javascript">
        var myApp = angular.module('myApp', []);

        myApp.factory('myService', function() {
            return {
                foo: function() {
                    alert("I'm foo!");
                }
            };
        });

        myApp.run(function($rootScope, myService) {
            $rootScope.appData = myService;
        });

        myApp.controller('MainCtrl', ['$scope', function($scope){

        }]);

    </script>
</head>
<body ng-controller="MainCtrl">
    <button ng-click="appData.foo()">Call foo</button>
</body>
</html>

7
ฉันคิดว่านี่ควรเป็นคำตอบที่ถูกต้องโดยคำตอบของ @Praym มันไม่มีเหตุผลที่ระบุการพึ่งพาบริการใน 10 คอนโทรลเลอร์ที่แตกต่างกัน
jvannistelrooy

บริการสามารถรวมวิธีการ / ฟังก์ชั่นที่สามารถคุณสมบัติ CRUD / ตัวแปรใน$rootScope?
jezmck

44

แม้ว่าวิธีการแรกจะได้รับการสนับสนุนในฐานะ 'เชิงมุมคล้าย' แต่ฉันรู้สึกว่านี่จะเพิ่มค่าใช้จ่าย

พิจารณาว่าฉันต้องการใช้ฟังก์ชั่น myservice.foo นี้ในคอนโทรลเลอร์ 10 ตัวที่แตกต่างกันหรือไม่ ฉันจะต้องระบุการพึ่งพา 'myService' นี้จากนั้น $ scope.callFoo คุณสมบัติขอบเขตในทั้งสิบรายการ นี่เป็นเพียงการกล่าวซ้ำ ๆ และเป็นการละเมิดหลักการ DRY

ในขณะที่ถ้าฉันใช้วิธี $ rootScope ฉันจะระบุฟังก์ชั่นทั่วโลกนี้ gobalFoo เพียงครั้งเดียวและมันจะมีอยู่ในตัวควบคุมในอนาคตของฉันทั้งหมดไม่ว่าจะมีจำนวนเท่าใด


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

มันจะต้องมีการวางในขอบเขตถ้าคุณต้องการที่จะเรียกมันจากมุมมอง ในตัวควบคุมคุณสามารถโทรได้โดยตรงจากบริการ
mcv

10
นี่คือความคิดเห็นไม่ใช่คำตอบ
Elliott

ตัวแปร $ rootScope เป็นโมฆะเมื่อรีเฟรชหน้าในกรณีนี้คุณจะไม่ได้รับฟังก์ชั่น นั่นเป็นเหตุผลที่ดีที่จะฉีดบริการและใช้การอ้างอิงในแอปพลิเคชัน
Ehsan Hafeez

4

AngularJs มี " บริการ " และ " โรงงาน " เพียงสำหรับปัญหาเช่นคุณของคุณเหล่านี้จะใช้ในการมีบางสิ่งบางอย่างทั่วโลกระหว่างตัวควบคุมคำสั่งบริการอื่น ๆ หรือส่วนประกอบเชิงมุมอื่น ๆ .. คุณสามารถกำหนดฟังก์ชั่นจัดเก็บข้อมูล ต้องการภายในบริการและใช้ใน AngularJs Components เป็นGlobal. like

angular.module('MyModule', [...])
  .service('MyService', ['$http', function($http){
    return {
       users: [...],
       getUserFriends: function(userId){
          return $http({
            method: 'GET',
            url: '/api/user/friends/' + userId
          });
       }
       ....
    }
  }])

ถ้าคุณต้องการมากขึ้น

ค้นหาข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุที่เราต้องการบริการและโรงงานของ AngularJs


0

ฉันค่อนข้างใหม่กับ Angular แต่สิ่งที่ฉันพบว่ามีประโยชน์ในการทำ (และค่อนข้างง่าย) คือฉันสร้างสคริปต์สากลที่ฉันโหลดลงบนหน้าเว็บของฉันก่อนหน้าสคริปต์ท้องถิ่นที่มีตัวแปรทั่วโลกที่ฉันต้องการเข้าถึงในทุกหน้า ในสคริปต์นั้นฉันสร้างวัตถุที่เรียกว่า "globalFunctions" และเพิ่มฟังก์ชั่นที่ฉันต้องการในการเข้าถึงทั่วโลกเป็นคุณสมบัติ globalFunctions.foo = myFunc();เช่น จากนั้นในแต่ละสคริปต์ท้องถิ่นฉันเขียน$scope.globalFunctions = globalFunctions;และฉันสามารถเข้าถึงฟังก์ชั่นใด ๆ ที่ฉันเพิ่มไปยังวัตถุ globalFunctions ในสคริปต์สากลได้ทันที

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


1
ฉันแค่อยากรู้ว่าทำไม downvotes? ฉันใหม่และอยากจะรู้จากข้อดี
Izzy

ดูเหมือนว่าเป็นวิธีแก้ปัญหาการทำงานให้ฉัน สิ่งเดียวที่ฉันจะสนับสนุนเพื่อให้แน่ใจว่าขอบเขตของคุณถูกแยกออกจากกันอย่างเพียงพอคือการสร้างคลาสยูทิลิตี้ Javascript รูทส่วนกลางและวางเมธอดยูทิลิตี้ของคุณไว้เพื่อที่ว่าคุณจะไม่ได้ตั้งใจทำงานชื่ออื่น ๆ ทะเลอันกว้างใหญ่ของสิ่งต่าง ๆ ที่ฉีดโดยแองกูลาร์
JE Carter II

สิ่งหนึ่งที่ควรทราบและอาจเป็นเพราะเหตุนี้ downvote คุณสามารถใช้ฟังก์ชันเหล่านั้นในแม่แบบของคุณเท่านั้นไม่ใช่โมดูล. ts เนื่องจากการเรียกใช้ฟังก์ชันของคุณจะไม่สามารถแก้ไขได้ในเวลารวบรวม นี่คือเหตุผลในการทำแบบ "เชิงมุม" แต่ถ้าคุณต้องการเพิ่มมัณฑนากรและเทมเพลตของคุณไฟล์ยูทิลิตี้ระดับโลกนั้นเรียบง่ายและดี
JE Carter II
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.