Angularjs. Denetleyici işlevinin denetleyici bileşeninin dışından nasıl çağrılacağı


190

Denetleyici altında tanımlanan işlevi web sayfasının herhangi bir yerinden (denetleyici bileşeninin dışında) nasıl arayabilirim?

"Al" düğmesine bastığımda mükemmel çalışıyor. Ama div denetleyicisinin dışından aramam gerekiyor. Mantık: varsayılan olarak div bölümüm gizlidir. Navigasyon menüsünde bir yerde bir düğmeye basıyorum ve div () bölümümü göstermeli ve "get" işlevini uygulamalıdır. Bunu nasıl başarabilirim?

Web sayfam:

<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>

Benim js:

   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
"... navigasyon menüsünün herhangi bir yerinde bir düğmeye basarsanız ..." derken, bu navigasyonun başka bir kontrol cihazının parçası olduğunu ve get()MyController'ı başka bir kontrol cihazından aramak istediğinizi mi söylemek istersiniz ?
callmekatootie

1
Şimdilik navigasyon menüsü bir kontrolör değil. Sadece html. Denetleyici işlevini html / javascript'ten aramak mümkün olup olmadığından emin değilim, bu yüzden bu soruyu gönderdim. Ama evet, navigasyon menüsünü ayrı bir kontrolör olarak yapmak mantıklı. MyController.get () işlevini NavigationMenu.Controller'dan nasıl çağırabilirim?
Pavel Zdarov

Yanıtlar:


331

Denetleyicinin işlevini dışarıdan çağırmanın bir yolu:

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

get()denetleyicinizden bir işlev nerede .

Geçiş yapabilirsiniz

document.getElementById('yourControllerElementID')` 

için

$('#yourControllerElementID')

JQuery kullanıyorsanız.

Ayrıca, işleviniz Görünümünüzdeki herhangi bir şeyi değiştirmek anlamına geliyorsa,

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

değişiklikleri uygulamak için.

Dikkat etmeniz gereken bir nokta daha var: Kapsamlar sayfa yüklendikten sonra başlatıldığından, kapsam dışından çağrı yöntemlerinin her zaman sayfa yüklendikten sonra yapılması gerekir. Yoksa hiç kapsama girmeyeceksiniz.

GÜNCELLEME:

Açısal en son sürümlerinde,

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

Ve evet, bu aslında kötü bir uygulamadır , ancak bazen sadece hızlı ve kirli işlere ihtiyacınız vardır.



8
DOM kodunu Açısal kodla karıştırmanız gerekmiyorsa, belirli JQuery animasyonlarının Açısal denetleyicinizdeki değişken bir değişime tepki olarak patlamasını istiyorsanız, bunu tam olarak nasıl yapıyorsunuz? Denetleyiciden yapmak önemsiz olurdu, ancak temiz bir şekilde nasıl yapacağımı bilmiyorum
Jan

3
$applyKodu bir işleve, ör...scope.$apply(function() { scope.get() });
surfitscrollit

2
Aslında angular.element(document.getElementById('yourControllerElementID')).scope().controller; For ile denetleyiciye erişebildim . eğer kullanım: angular.element(document.getElementById('controller')).scope().get() atar ve tanımsız hata, ama ben kullanırsam angular.element(document.getElementById('controller')).scope().controller.get()çalışır.
vrunoa

2
Bu çözümün artık Açısal 1.4.9'da çalışmadığı mümkün mü? Ben erişemiyor scope()içinde angular.element(...)o tanımsız ve açısal eleman / nesnenin bir vardump fonksiyonu söylüyor dönüş çünkü scopeiçinde yer almaktadır __proto__-Nesne.
Smamatti

37

İnternette bir örnek buldum.

Bazı çocuklar bu kodu yazdı ve mükemmel çalıştı

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);
    });
}

gösteri

* Bazı değişiklikler yaptım, orijinal görün: font JSfiddle


2
Teşekkürler Roger, çok yararlı!
Eduardo

Kullanılması GEREKEN eski bir jQuery doğrulama kitaplığı ile çalışma. Yani, ya 1: kütüphaneyi yeniden yazın, 2: kütüphaneyi sarmak için direktif oluşturun, geçerli olduğunda açısal gönderimi çağırmak için 3: 2 kod satırı ...
Michael K

Uygula seçeneğini kullanmazsam, görünüm verilerini güncelleyecek işlev yansıtılmaz mı?
Monojit Sarkar

13

Çözüm angular.element(document.getElementById('ID')).scope().get()benim için açısal 1.5.2'de çalışmayı durdurdu. Birisi yorumda 1.4.9'da da işe yaramadığını belirtti. Kapsamı global bir değişkende saklayarak düzelttim:

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

özel koddan çağrı:

scopeHolder.bar()

kapsamı yalnızca bu yöntemle sınırlamak istiyorsanız. Tüm kapsamın maruz kalmasını en aza indirmek. aşağıdaki tekniği kullanın.

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

özel koddan çağrı:

scopeHolder()

Bu benim için harika çalıştı (bir bileşenin içinden bile). Bunu sadece benim senaryomda kaçınamayacağım "dış açısal açısal şeyleri çağırmak için kötü uygulama" dışında bir dezavantajı var mı? stackoverflow.com/questions/42123120/…
RichC

Yardımınız için teşekkürler efendim bir süredir bunun için bir çözüm arıyordum
İbrahim Amer

11

Dmitry'nin cevabı iyi çalışıyor. Aynı tekniği kullanarak basit bir örnek verdim.

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

Fabrikayı kendi kod satırı ile enjekte etmekten ziyade kontrolörlere bağımlılık olarak eklemeyi tercih ederim: http://jsfiddle.net/XqDxG/550/

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

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

ControllerZero. $ İnject = ['$ scope', 'mySharedService'];


Hmm. @Anton, aşağıda (Mayıs '13'te) İKİ yapan bir keman yorumladı.
Jesse Chisholm

5

Menünüzün herhangi bir ilişkili kapsam olmadan sahip olmanın doğru yol olup olmadığını düşünmek faydalı olabilir. Bu gerçekten açısal bir yol değil.

Ancak, gitmeniz gereken yol buysa, işlevleri $ rootScope'a ekleyerek ve ardından bu işlevleri içinde olay göndermek için $ broadcast kullanarak yapabilirsiniz. denetleyiciniz daha sonra bu olayları dinlemek için $ on kullanır.

Menünüzü bir kapsam olmadan elde ederseniz, göz önünde bulundurmanız gereken başka bir şey, birden fazla rotanız varsa, tüm denetleyicilerinizin kendi upate ve işlevlerine sahip olması gerektiğidir. (bu, birden fazla denetleyiciniz olduğunu varsayar)


ControllerTwo'dan ControllerOne'un .get () işlevinin nasıl çağrıldığına dair basit bir örnek verebilir misiniz? mantığım bu yüzden her denetleyicinin kendi .get () .update () işlevleri olacaktır. Gerekli denetleyicinin (menü öğesine göre) .get () yürütmem gereken MainMenuController'a sahip olacağım.
Pavel Zdarov

ps, benim kodum değil, ancak birden fazla denetleyicinin işlevsellik paylaşımı nasıl olacağını gösterir
Anton

4

Ben bir kaynaktan bazı bilgi almak istediğinizde ben $ http ile çalışmak için kullanın, ben aşağıdakileri yapmak:

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);
    }}
    });

Ve denetleyicideki kod:

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);
    }
}

Servise kontrolörde hangi fonksiyonun çağırılması gerektiğini gönderirim


3

Birden fazla rotam ve birden fazla denetleyicim var, bu yüzden çalışmak için kabul edilen cevabı alamadım. Pencereye işlev eklemenin işe yaradığını gördüm:

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;

}

Daha sonra kontrolörün dışında bu yapılabilir:

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

0

Kontrolörün dışından Açısal Kapsam işlevini çağırın.

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

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

-1

Ben bir İyonik çerçeve kullanıcısıyım ve sürekli olarak mevcut kontrolörün $ kapsamını sağlayacak bulduğum kişi:

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

Sadece belirli bir denetleyici örneği sırasında kullanılabilir belirli DOM öğelerini hedefleyecek sorguyu bularak çerçeve (ya da değil) çoğu senaryo uyacak şekilde değiştirilebileceğinden şüpheleniyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.