AngularJS. Cách gọi chức năng điều khiển từ bên ngoài thành phần điều khiển


190

Làm cách nào tôi có thể gọi hàm được xác định trong bộ điều khiển từ bất kỳ vị trí nào của trang web (bên ngoài thành phần của bộ điều khiển)?

Nó hoạt động hoàn hảo khi tôi nhấn nút "get". Nhưng tôi cần gọi nó từ bên ngoài bộ điều khiển div. Logic là: theo mặc định div của tôi bị ẩn. Ở đâu đó trong menu điều hướng, tôi nhấn một nút và nó sẽ hiển thị () div của tôi và thực hiện chức năng "get". Làm thế nào tôi có thể đạt được điều này?

Trang web của tôi là:

<div ng-controller="MyController">
  <input type="text" ng-model="data.firstname" required>
  <input type='text' ng-model="data.lastname" required>

  <form ng-submit="update()"><input type="submit" value="update"></form>
  <form ng-submit="get()"><input type="submit" value="get"></form>
</div>

Js của tôi:

   function MyController($scope) {
      // default data and structure
      $scope.data = {
        "firstname" : "Nicolas",
        "lastname" : "Cage"
      };

      $scope.get = function() {
        $.ajax({
           url: "/php/get_data.php?",
           type: "POST",
           timeout: 10000, // 10 seconds for getting result, otherwise error.
           error:function() { alert("Temporary error. Please try again...");},
           complete: function(){ $.unblockUI();},
           beforeSend: function(){ $.blockUI()},
           success: function(data){
            json_answer = eval('(' + data + ')');
            if (json_answer){
                $scope.$apply(function () {
                  $scope.data = json_answer;
            });
            }
        }
    });
  };

  $scope.update = function() {
    $.ajax({
        url: "/php/update_data.php?",
        type: "POST",
        data: $scope.data,
        timeout: 10000, // 10 seconds for getting result, otherwise error.
        error:function() { alert("Temporary error. Please try again...");},
        complete: function(){ $.unblockUI();},
        beforeSend: function(){ $.blockUI()},
        success: function(data){ }
      });
    };
   }

2
Khi bạn nói "... ở đâu đó trong menu điều hướng, bạn nhấn một nút ...", bạn có nghĩa là điều hướng này là một phần của bộ điều khiển khác và bạn muốn gọi get()MyContoder từ bộ điều khiển khác?
callmekatootie

1
Bây giờ menu điều hướng không phải là một bộ điều khiển. Chỉ cần html. Không chắc chắn nếu có thể gọi chức năng điều khiển từ html / javascript, đó là lý do tại sao tôi đăng câu hỏi này. Nhưng vâng, hợp lý để làm menu điều hướng như bộ điều khiển riêng biệt. Làm cách nào tôi có thể gọi hàm MyControll.get () từ NavigationMothy.Controll?
Pavel Zdarov

Câu trả lời:


331

Đây là một cách để gọi chức năng của bộ điều khiển từ bên ngoài nó:

angular.element(document.getElementById('yourControllerElementID')).scope().get();

Ở đâu get() là một chức năng từ bộ điều khiển của bạn.

Bạn có thể chuyển đổi

document.getElementById('yourControllerElementID')` 

đến

$('#yourControllerElementID')

Nếu bạn đang sử dụng jQuery.

Ngoài ra, nếu chức năng của bạn có nghĩa là thay đổi bất cứ điều gì trên Chế độ xem của bạn, bạn nên gọi

angular.element(document.getElementById('yourControllerElementID')).scope().$apply();

để áp dụng các thay đổi.

Một điều nữa, bạn cần lưu ý là phạm vi được khởi tạo sau khi trang được tải, do đó, các phương thức gọi từ bên ngoài phạm vi phải luôn được thực hiện sau khi trang được tải. Khác, bạn sẽ không nhận được phạm vi ở tất cả.

CẬP NHẬT:

Với các phiên bản mới nhất của góc, bạn nên sử dụng

angular.element(document.getElementById('yourControllerElementID')).injector().‌​get('$rootScope')

Và vâng, trên thực tế, đây là một thực tế tồi tệ , nhưng đôi khi bạn chỉ cần mọi thứ được thực hiện nhanh chóng và bẩn thỉu.


30
Điều này có vẻ giống như mùi mã vì triết lý của Angular là không trộn mã DOM với mã Angular ...
JoeCool

8
vì vậy, nếu bạn không cần phải trộn mã DOM với mã Angular, nếu bạn muốn một số hoạt hình JQuery nhất định tắt để phản ứng với sự thay đổi biến trong bộ điều khiển Angular của bạn - bạn chính xác làm thế nào? Nó sẽ là không quan trọng để làm từ bộ điều khiển, nhưng tôi không biết làm thế nào để làm điều đó sạch sẽ
ngày 1 tháng

3
Tôi không thể có được $applymột phần công việc cho tôi, cho đến khi tôi quấn mã vào một chức năng, ví dụ..scope.$apply(function() { scope.get() });
surfitscrollit

2
Tôi thực sự có thể truy cập bộ điều khiển với angular.element(document.getElementById('yourControllerElementID')).scope().controller; For ex. nếu sử dụng: angular.element(document.getElementById('controller')).scope().get() ném và lỗi không xác định, nhưng nếu tôi sử dụng angular.element(document.getElementById('controller')).scope().controller.get()nó hoạt động.
vuggoa 4/2/2015

2
Có thể, giải pháp này không còn hoạt động trong Angular 1.4.9 nữa? Tôi không thể truy cập scope()vào angular.element(...), bởi vì nó trả về không xác định và phần tử của phần tử / đối tượng góc nói rằng hàm scopenằm trong __proto__-object.
Smamatti

37

Tôi đã tìm thấy một ví dụ trên internet.

Một số người đã viết mã này và làm việc hoàn hảo

HTML

<div ng-cloak ng-app="ManagerApp">
    <div id="MainWrap" class="container" ng-controller="ManagerCtrl">
       <span class="label label-info label-ext">Exposing Controller Function outside the module via onClick function call</span>
       <button onClick='ajaxResultPost("Update:Name:With:JOHN","accept",true);'>click me</button>
       <br/> <span class="label label-warning label-ext" ng-bind="customParams.data"></span>
       <br/> <span class="label label-warning label-ext" ng-bind="customParams.type"></span>
       <br/> <span class="label label-warning label-ext" ng-bind="customParams.res"></span>
       <br/>
       <input type="text" ng-model="sampletext" size="60">
       <br/>
    </div>
</div>

JAVASCRIPT

var angularApp = angular.module('ManagerApp', []);
angularApp.controller('ManagerCtrl', ['$scope', function ($scope) {

$scope.customParams = {};

$scope.updateCustomRequest = function (data, type, res) {
    $scope.customParams.data = data;
    $scope.customParams.type = type;
    $scope.customParams.res = res;
    $scope.sampletext = "input text: " + data;
};



}]);

function ajaxResultPost(data, type, res) {
    var scope = angular.element(document.getElementById("MainWrap")).scope();
    scope.$apply(function () {
    scope.updateCustomRequest(data, type, res);
    });
}

Bản giới thiệu

* Tôi đã thực hiện một số sửa đổi, xem bản gốc: font JSfiddle


2
Cảm ơn Roger, rất hữu ích!
Eduardo

Làm việc với thư viện xác thực jQuery kế thừa PHẢI được sử dụng. Vì vậy, đó là 1: viết lại thư viện, 2: tạo lệnh để bọc thư viện, các dòng mã 3: 2 để gọi trình gửi góc khi hợp lệ ...
Michael K

Nếu tôi không sử dụng áp dụng thì chức năng sẽ cập nhật dữ liệu xem sẽ không được phản ánh?
Monojit Sarkar

13

Các giải pháp angular.element(document.getElementById('ID')).scope().get()ngừng hoạt động cho tôi trong góc 1.5.2. Sombody đề cập trong một bình luận rằng điều này cũng không hoạt động trong 1.4.9. Tôi đã sửa nó bằng cách lưu trữ phạm vi trong một biến toàn cục:

var scopeHolder;
angular.module('fooApp').controller('appCtrl', function ($scope) {
    $scope = function bar(){
        console.log("foo");        
    };
    scopeHolder = $scope;
})

gọi từ mã tùy chỉnh:

scopeHolder.bar()

nếu bạn muốn giới hạn phạm vi chỉ phương pháp này. Để giảm thiểu tiếp xúc của toàn bộ phạm vi. sử dụng kỹ thuật sau.

var scopeHolder;
angular.module('fooApp').controller('appCtrl', function ($scope) {
    $scope.bar = function(){
        console.log("foo");        
    };
    scopeHolder = $scope.bar;
})

gọi từ mã tùy chỉnh:

scopeHolder()

Điều này làm việc rất tốt cho tôi (thậm chí từ bên trong một thành phần). Có một nhược điểm nào khi làm điều này ngoài việc chỉ là "thực hành tồi để gọi những thứ góc cạnh từ góc bên ngoài" mà tôi không thể tránh trong kịch bản của mình? stackoverflow.com/questions/42123120/
Mạnh

Cảm ơn sự giúp đỡ của bạn, tôi đã tìm kiếm một giải pháp cho vấn đề này trong một thời gian
Ibrahim Amer

11

Câu trả lời của Dmitry hoạt động tốt. Tôi chỉ làm một ví dụ đơn giản bằng cách sử dụng kỹ thuật tương tự.

jsfiddle: http://jsfiddle.net/o895a8n8/5/

<button onclick="call()">Call Controller's method from outside</button>
<div  id="container" ng-app="" ng-controller="testController">
</div>

.

function call() {
    var scope = angular.element(document.getElementById('container')).scope();
      scope.$apply(function(){
        scope.msg = scope.msg + ' I am the newly addded message from the outside of the controller.';
    })
    alert(scope.returnHello());
}

function testController($scope) {
    $scope.msg = "Hello from a controller method.";
    $scope.returnHello = function() {
        return $scope.msg ; 
    }
}

7

Tôi thà bao gồm nhà máy là phụ thuộc vào các bộ điều khiển hơn là tiêm chúng với dòng mã riêng của họ: http://jsfiddle.net/XqDxG/550/

myModule.factory('mySharedService', function($rootScope) {
    return sharedService = {thing:"value"};
});

function ControllerZero($scope, mySharedService) {
    $scope.thing = mySharedService.thing;

Bộ điều khiểnZero. $ Tiêm = ['$ scope', 'mySharedService'];


Hừm. @Anton đã nhận xét một câu đố dưới đây (vào tháng 5 năm 13) mà CẢ.
Jesse Chisholm

5

Có thể đáng cân nhắc nếu có thực đơn của bạn mà không có bất kỳ phạm vi liên quan nào là cách phù hợp. Nó không thực sự là cách góc cạnh.

Nhưng, nếu đó là con đường bạn cần đi, thì bạn có thể thực hiện bằng cách thêm các hàm vào $ rootScope và sau đó trong các hàm đó bằng cách sử dụng $ Broadcast để gửi sự kiện. bộ điều khiển của bạn sau đó sử dụng $ on để lắng nghe những sự kiện đó.

Một điều khác cần xem xét nếu cuối cùng bạn có menu của mình mà không có phạm vi là nếu bạn có nhiều tuyến đường, thì tất cả các bộ điều khiển của bạn sẽ phải có chức năng nâng cấp riêng và nhận chức năng. (đây là giả sử bạn có nhiều bộ điều khiển)


bạn có thể đưa ra bất kỳ ví dụ đơn giản nào về cách gọi hàm .get () của ControllerOne từ ControllerTwo không? logic của tôi là vì vậy mỗi bộ điều khiển sẽ có các hàm .get () .update () riêng. Tôi sẽ có MainMothyContoder mà tôi cần thực thi (theo mục menu) .get () của bộ điều khiển cần thiết.
Pavel Zdarov

ps, không phải mã của tôi, nhưng nó cho thấy làm thế nào để có nhiều chức năng chia sẻ bộ điều khiển
Anton

4

Tôi sử dụng để làm việc với $ http, khi muốn nhận một số thông tin từ tài nguyên tôi thực hiện như sau:

angular.module('services.value', [])

.service('Value', function($http, $q) {

var URL = "http://localhost:8080/myWeb/rest/";

var valid = false;

return {
    isValid: valid,
    getIsValid: function(callback){
        return $http.get(URL + email+'/'+password, {cache: false})
                    .success(function(data){
            if(data === 'true'){ valid = true; }
        }).then(callback);
    }}
    });

Và mã trong bộ điều khiển:

angular.module('controllers.value', ['services.value'])

.controller('ValueController', function($scope, Value) {
    $scope.obtainValue = function(){
        Value.getIsValid(function(){$scope.printValue();});
    }

    $scope.printValue = function(){
        console.log("Do it, and value is " Value.isValid);
    }
}

Tôi gửi đến dịch vụ chức năng nào phải gọi trong bộ điều khiển


3

Tôi có nhiều tuyến đường và nhiều bộ điều khiển, vì vậy tôi không thể có câu trả lời được chấp nhận để làm việc. Tôi thấy rằng việc thêm chức năng vào cửa sổ hoạt động:

fooModule.controller("fooViewModel", function ($scope, fooService, $http, $q, $routeParams, $window, $location, viewModelHelper, $interval) {
    $scope.initFoo = function () {
        // do angular stuff
    }
    var initialize = function () {
        $scope.initFoo();
    }

    initialize();

    window.fooreinit = initialize;

}

Sau đó, bên ngoài bộ điều khiển, điều này có thể được thực hiện:

function ElsewhereOnThePage() {
    if (typeof(fooreinit) == 'function') { fooreinit(); }
}

0

Gọi chức năng Angular Scope từ bên ngoài bộ điều khiển.

// Simply Use "Body" tag, Don't try/confuse using id/class.

var scope = angular.element('body').scope();             
scope.$apply(function () {scope.YourAngularJSFunction()});      

-1

Tôi là người dùng khung Ionic và người tôi thấy sẽ luôn cung cấp phạm vi $ của bộ điều khiển hiện tại là:

angular.element(document.querySelector('ion-view[nav-view="active"]')).scope()

Tôi nghi ngờ điều này có thể được sửa đổi để phù hợp với hầu hết các kịch bản bất kể khung (hoặc không) bằng cách tìm truy vấn sẽ nhắm mục tiêu (các) phần tử DOM cụ thể chỉ khả dụng trong một phiên bản điều khiển cụ thể.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.