Diğer denetleyiciden yönerge denetleyicisindeki çağrı yöntemi


118

Kendi denetleyicisi olan bir yönergem var. Aşağıdaki koda bakın:

var popdown = angular.module('xModules',[]);

popdown.directive('popdown', function () {
    var PopdownController = function ($scope) {
        this.scope = $scope;
    }

    PopdownController.prototype = {
        show:function (message, type) {
            this.scope.message = message;
            this.scope.type = type;
        },

        hide:function () {
            this.scope.message = '';
            this.scope.type = '';
        }
    }

    var linkFn = function (scope, lElement, attrs, controller) {

    };

    return {
        controller: PopdownController,
        link: linkFn,
        replace: true,
        templateUrl: './partials/modules/popdown.html'
    }

});

Bu, hatalar / bildirimler / uyarılar için bir bildirim sistemi anlamına gelir. Yapmak istediğim şey, başka bir denetleyiciden (bir yönerge değil) showbu denetleyicideki işlevi çağırmaktır . Ve bunu yaptığımda, bağlantı işlevimin bazı özelliklerin değiştiğini algılamasını ve bazı animasyonları gerçekleştirmesini de isterim.

İşte istediğim şeyi örneklemek için bazı kodlar:

var app = angular.module('app', ['RestService']);

app.controller('IndexController', function($scope, RestService) {
    var result = RestService.query();

    if(result.error) {
        popdown.notify(error.message, 'error');
    }
});

Dolayısıyla show, popdownyönerge denetleyicisini çağırırken , bağlantı işlevi de tetiklenmeli ve bir animasyon gerçekleştirmelidir. Bunu nasıl başarabilirim?


popdownYönerge çağrısını sayfadaki nereye yerleştiriyorsunuz - diğer denetleyicilerin hepsinin ona erişmesi gereken tek bir yerde mi yoksa farklı yerlerde birkaç açılır pencere var mı?
satchmorun

benim index.html'm şuna sahip: <div ng-view> </div> <div popdown> </div> temelde, küresel olarak kullanılabilir olması amaçlanan sadece 1 açılır pencere örneği var.
user253530

1
Bence bunun popdown.show(...)yerine yazmak istedin, popdown.notify(...)doğru mu? Aksi takdirde bildirim işlevi biraz kafa karıştırıcıdır.
lanoxx

o nereden geliyor popdown.notify? .notifiyyöntem, yani
Green

Yanıtlar:


167

Bu ilginç bir soru ve böyle bir şeyi nasıl uygulayacağımı düşünmeye başladım.

Bunu buldum (keman) ;

Temel olarak, bir denetleyiciden bir yönerge çağırmaya çalışmak yerine, tüm açılır pencere mantığını barındıracak bir modül oluşturdum:

var PopdownModule = angular.module('Popdown', []);

Modüle iki şey koydum, factoryher yere enjekte edilebilen API directiveiçin ve gerçek açılır pencerenin davranışını tanımlamak için:

Fabrikası sadece işlevlerin bir çift tanımlar successve errorve değişkenlerin bir çift izler:

PopdownModule.factory('PopdownAPI', function() {
    return {
        status: null,
        message: null,
        success: function(msg) {
            this.status = 'success';
            this.message = msg;
        },
        error: function(msg) {
            this.status = 'error';
            this.message = msg;
        },
        clear: function() {
            this.status = null;
            this.message = null;
        }
    }
});

Yönerge, API'nin denetleyicisine enjekte edilmesini sağlar ve API'yi değişiklikler için izler (kolaylık sağlamak için bootstrap css kullanıyorum):

PopdownModule.directive('popdown', function() {
    return {
        restrict: 'E',
        scope: {},
        replace: true,
        controller: function($scope, PopdownAPI) {
            $scope.show = false;
            $scope.api = PopdownAPI;

            $scope.$watch('api.status', toggledisplay)
            $scope.$watch('api.message', toggledisplay)

            $scope.hide = function() {
                $scope.show = false;
                $scope.api.clear();
            };

            function toggledisplay() {
                $scope.show = !!($scope.api.status && $scope.api.message);               
            }
        },
        template: '<div class="alert alert-{{api.status}}" ng-show="show">' +
                  '  <button type="button" class="close" ng-click="hide()">&times;</button>' +
                  '  {{api.message}}' +
                  '</div>'
    }
})

Sonra appşunlara bağlı olan bir modül tanımlıyorum Popdown:

var app = angular.module('app', ['Popdown']);

app.controller('main', function($scope, PopdownAPI) {
    $scope.success = function(msg) { PopdownAPI.success(msg); }
    $scope.error   = function(msg) { PopdownAPI.error(msg); }
});

Ve HTML şöyle görünür:

<html ng-app="app">
    <body ng-controller="main">
        <popdown></popdown>
        <a class="btn" ng-click="success('I am a success!')">Succeed</a>
        <a class="btn" ng-click="error('Alas, I am a failure!')">Fail</a>
    </body>
</html>

Tamamen ideal olup olmadığından emin değilim, ancak küresel bir açılır menü yönergesiyle iletişim kurmanın makul bir yolu gibi görünüyordu.

Yine referans için keman .


10
+1 Direktifin dışından bir direktifte bir işlevi asla çağırmamalı - bu kötü bir uygulamadır. Bir direktifin okuduğu küresel durumu yönetmek için bir hizmet kullanmak çok yaygındır ve bu doğru yaklaşımdır. Diğer uygulamalar arasında bildirim kuyrukları ve kalıcı iletişim kutuları bulunur.
Josh David Miller

7
Gerçekten olağanüstü cevap! JQuery ve Backbone'dan gelen bizler için çok faydalı bir örnek
Brandon

11
Bu şekilde, bu modülü aynı görünümde birden çok yönergeyi somutlaştırmak için kullanmak mümkün müdür? Bu direktifin belirli bir örneğinin başarı veya hata işlevini nasıl çağırabilirim?
ira

3
@ira, muhtemelen durum ve mesaj nesnelerinin bir haritasını (veya listesini) tutmak için fabrikayı değiştirebilir ve ardından listedeki hangi öğeye ihtiyacınız olduğunu belirlemek için direktifte bir ad niteliği kullanabilirsiniz. Bu yüzden html'de arama success(msg)yapmak yerine sucess(name, msg), direktifi doğru isimle seçmek için çağırırsınız .
lanoxx

5
@JoshDavidMiller neden bir yönergede bir yöntem çağırmanın kötü bir uygulama olduğunu düşünüyorsunuz? Bir yönerge, bazı DOM mantığını amaçlandığı gibi kapsüllerse, bir API'yi açığa çıkarmak kesinlikle doğaldır, böylece onu kullanan denetleyiciler, kendi yöntemlerini gerektiği gibi çalıştırabilir?
Paul Taylor

27

Popdown'u tetiklemek için olayları da kullanabilirsiniz.

İşte satchmorun'un çözümüne dayanan bir keman . PopdownAPI ve üst düzey denetleyici yerine $broadcastkapsam zincirindeki "başarılı" ve "hata" olaylarını ortadan kaldırır :

$scope.success = function(msg) { $scope.$broadcast('success', msg); };
$scope.error   = function(msg) { $scope.$broadcast('error', msg); };

Açılır modül daha sonra bu olaylar için işleyici işlevlerini kaydeder, örneğin:

$scope.$on('success', function(event, msg) {
    $scope.status = 'success';
    $scope.message = msg;
    $scope.toggleDisplay();
});

Bu en azından işe yarıyor ve bana güzel bir şekilde ayrılmış bir çözüm gibi görünüyor. Bu bazı nedenlerden dolayı kötü bir uygulama olarak kabul edilirse, başkalarının konuşmasına izin vereceğim.


1
Aklıma gelen bir dezavantaj, seçilen yanıtta yalnızca PopdownAPI'ye (DI ile kolayca erişilebilir) ihtiyacınız olmasıdır. Bunda, mesajı yayınlamak için kontrolörün kapsamına erişmeniz gerekir. Her neyse, çok kısa görünüyor.
Julian

Bunu, karmaşıklığı azalttığı ve hala gevşek bir şekilde bağlı olduğu için basit kullanım durumları için hizmet yaklaşımından daha çok seviyorum
Patrick Favre

11

Gibi Ayrıca, ebeveyn kapsamına yönerge denetleyicisi maruz bırakabilir ngFormile namenitelik yapar: http://docs.angularjs.org/api/ng.directive:ngForm

Burada bunun nasıl elde edilebileceğine dair çok basit bir örnek bulabilirsiniz http://plnkr.co/edit/Ps8OXrfpnePFvvdFgYJf?p=preview

Bu örnekte myDirective, $clearyöntemli özel denetleyiciye sahibim (yönerge için çok basit bir genel API türü). Bu denetleyiciyi ana kapsamda yayınlayabilir ve bu yöntemi yönergenin dışında kullanabilirim.


Bu, kontrolörler arasında bir ilişki gerektirir, değil mi? OP bir mesaj merkezi istediğinden, bu onun için ideal olmayabilir. Ama yaklaşımınızı öğrenmek de çok güzeldi. Pek çok durumda kullanışlıdır ve dediğiniz gibi, açısal onu kullanır.
fasfsfgs

Satchmorun tarafından sağlanan bir örneği izlemeye çalışıyorum. Çalışma zamanında bazı html üretiyorum, ancak yönergenin şablonunu kullanmıyorum. Eklenen html'den çağrılacak bir işlev belirtmek için yönergenin denetleyicisini kullanıyorum, ancak işlev çağrılmıyor. Temel olarak şu yönergeye sahibim: directives.directive ('abcXyz', function ($ compile {return {restrict: 'AE', require: 'ngModel', controller: function ($ kapsam) {$ kapsam.function1 = function () {..};}, benim html şudur: "<a href="" ng-click="function1('itemtype')">
Mark

Direktif tekil değilse, api direktifini açığa çıkarabilecek tek zarif çözüm budur! Hala kullanmayı sevmiyorum $scope.$parent[alias]çünkü benim için iç açısal api kullanmak gibi kokuyor. Ancak yine de tekil olmayan yönergeler için daha zarif bir çözüm bulamıyorsunuz. Yayın olayları gibi diğer varyantlar veya yönerge api için ana denetleyicide boş nesne tanımlama gibi daha da fazla kokuyor.
Ruslan Stelmachenko

3

Çok daha iyi bir çözümüm var.

işte benim yönergem, yönergeye nesne başvurusu ekledim ve bunu yönerge koduna invoke işlevi ekleyerek genişlettim.

app.directive('myDirective', function () {
    return {
        restrict: 'E',
        scope: {
        /*The object that passed from the cntroller*/
        objectToInject: '=',
        },
        templateUrl: 'templates/myTemplate.html',

        link: function ($scope, element, attrs) {
            /*This method will be called whet the 'objectToInject' value is changes*/
            $scope.$watch('objectToInject', function (value) {
                /*Checking if the given value is not undefined*/
                if(value){
                $scope.Obj = value;
                    /*Injecting the Method*/
                    $scope.Obj.invoke = function(){
                        //Do something
                    }
                }    
            });
        }
    };
});

HTML'deki yönergeyi bir parametre ile bildirmek:

<my-directive object-to-inject="injectedObject"></ my-directive>

Denetleyicim:

app.controller("myController", ['$scope', function ($scope) {
   // object must be empty initialize,so it can be appended
    $scope.injectedObject = {};

    // now i can directly calling invoke function from here 
     $scope.injectedObject.invoke();
}];

Bu, temelde endişelerin ayrılması ilkelerine aykırı. Yönergeye bir denetleyicide somutlaştırılmış bir nesne sağlarsınız ve bu nesneyi yönetme sorumluluğunu (yani invoke işlevinin oluşturulması) yönergeye atarsınız. Bence daha iyi bir çözüm DEĞİL.
Florin Vistig
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.