Phương thức gọi trong bộ điều khiển chỉ thị từ bộ điều khiển khác


118

Tôi có một chỉ thị có bộ điều khiển riêng. Xem đoạn mã dưới đây:

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

});

Đây có nghĩa là một hệ thống thông báo cho các lỗi / thông báo / cảnh báo. Những gì tôi muốn làm là từ một bộ điều khiển khác (không phải là một chỉ thị) để gọi hàm showtrên bộ điều khiển này. Và khi tôi làm điều đó, tôi cũng muốn hàm liên kết của mình phát hiện ra rằng một số thuộc tính đã thay đổi và thực hiện một số hoạt ảnh.

Đây là một số mã để minh họa những gì tôi đang yêu cầu:

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

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

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

Vì vậy, khi gọi showtrên popdownbộ điều khiển chỉ thị, các chức năng liên kết nên cũng được kích hoạt và thực hiện một hình ảnh động. Làm thế nào tôi có thể đạt được điều đó?


Bạn đang đặt lệnh gọi tới popdownchỉ thị ở đâu trên trang - nó chỉ ở một nơi mà các bộ điều khiển khác được cho là có quyền truy cập vào nó, hay có một số cửa sổ bật xuống ở những nơi khác nhau?
satchmorun

index.html của tôi có cái này: <div ng-view> </div> <div popdown> </div> về cơ bản chỉ có 1 phiên bản popdown vì nó có nghĩa là có sẵn trên toàn cầu.
user253530,

1
Tôi nghĩ bạn muốn viết popdown.show(...)thay vì popdown.notify(...)điều đó có đúng không? Nếu không, chức năng thông báo là loại khó hiểu.
lanoxx

nó đến từ popdown.notifyđâu .notifiyphương pháp, ý tôi là
Xanh

Câu trả lời:


167

Đây là một câu hỏi thú vị, và tôi bắt đầu nghĩ về cách tôi sẽ triển khai một thứ như thế này.

Tôi đã nghĩ ra điều này (fiddle) ;

Về cơ bản, thay vì cố gắng gọi một chỉ thị từ bộ điều khiển, tôi đã tạo một mô-đun để chứa tất cả logic cửa sổ bật xuống:

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

Tôi đặt hai thứ vào mô-đun, một factorycho API có thể được đưa vào bất cứ đâu và directiveđể xác định hành vi của phần tử popdown thực tế:

Nhà máy chỉ định nghĩa một số hàm successerrortheo dõi một số biến:

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

Lệnh này đưa API vào bộ điều khiển của nó và xem api để biết các thay đổi (Tôi đang sử dụng bootstrap css để thuận tiện):

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

Sau đó, tôi xác định một appmô-đun phụ thuộc vào 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); }
});

Và HTML trông giống như:

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

Tôi không chắc liệu nó có hoàn toàn lý tưởng hay không, nhưng đây có vẻ là một cách hợp lý để thiết lập giao tiếp với chỉ thị popdown toàn cầu.

Một lần nữa, để tham khảo, fiddle .


10
+1 Người ta không bao giờ nên gọi một hàm trong một chỉ thị từ bên ngoài chỉ thị - đó là một phương pháp không tốt. Sử dụng một dịch vụ để quản lý trạng thái toàn cục mà một chỉ thị đọc là rất phổ biến và đây là cách tiếp cận đúng. Nhiều ứng dụng hơn bao gồm hàng đợi thông báo và hộp thoại phương thức.
Josh David Miller

7
Câu trả lời thực sự đặc biệt! Một ví dụ hữu ích cho những người trong chúng ta đến từ jQuery và Backbone
Brandon

11
Bằng cách này, có thể sử dụng mô-đun này để khởi tạo nhiều chỉ thị trong cùng một khung nhìn không? Làm cách nào để gọi hàm thành công hoặc hàm lỗi của một phiên bản cụ thể của chỉ thị này?
ira

3
@ira, bạn có thể thay đổi nhà máy để giữ một bản đồ (hoặc danh sách) các đối tượng trạng thái và thông báo, sau đó sử dụng thuộc tính tên trên chỉ thị để xác định mục nào trong danh sách bạn cần. Vì vậy, thay vì gọi success(msg)trong html, bạn sẽ gọi sucess(name, msg)để chọn chỉ thị với tên chính xác.
lanoxx

5
@JoshDavidMiller tại sao bạn lại coi việc gọi một phương thức trên một chỉ thị là một phương pháp không tốt? Nếu một chỉ thị đóng gói một số logic DOM như dự định, chắc chắn việc hiển thị một API để các bộ điều khiển sử dụng nó có thể gọi các phương thức của nó khi cần là điều khá tự nhiên?
Paul Taylor

27

Bạn cũng có thể sử dụng các sự kiện để kích hoạt Cửa sổ bật xuống.

Đây là một trò chơi dựa trên giải pháp của satchmorun. Nó phân phối với PopdownAPI và bộ điều khiển cấp cao nhất thay vào đó $broadcastlà các sự kiện 'thành công' và 'lỗi' trong chuỗi phạm vi:

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

Sau đó, mô-đun Popdown đăng ký các chức năng xử lý cho các sự kiện này, ví dụ:

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

Điều này ít nhất cũng hoạt động và đối với tôi dường như là một giải pháp tách biệt độc đáo. Tôi sẽ để những người khác kêu vang nếu đây được coi là hành động kém vì lý do nào đó.


1
Một nhược điểm mà tôi có thể nghĩ đến là trong câu trả lời đã chọn, bạn chỉ cần PopdownAPI (dễ dàng có sẵn với DI). Trong cái này, bạn cần truy cập vào phạm vi của bộ điều khiển để phát thông báo. Dù sao, nó trông rất ngắn gọn.
Julian

Tôi như thế này tốt hơn so với phương pháp-dịch vụ đối với trường hợp sử dụng đơn giản như nó giữ xuống phức tạp và vẫn còn lỏng lẻo
Patrick Favre

11

Bạn cũng có thể hiển thị trình điều khiển của chỉ thị với phạm vi chính, giống như ngFormvới namethuộc tính: http://docs.angularjs.org/api/ng.directive:ngForm

Ở đây, bạn có thể tìm thấy một ví dụ rất cơ bản về cách nó có thể đạt được http://plnkr.co/edit/Ps8OXrfpnePFvvdFgYJf?p=preview

Trong ví dụ này, tôi có myDirectivebộ điều khiển chuyên dụng với $clearphương thức (loại API công khai rất đơn giản cho chỉ thị). Tôi có thể xuất bản bộ điều khiển này đến phạm vi chính và sử dụng phương thức này bên ngoài chỉ thị.


Điều này đòi hỏi một mối quan hệ giữa các bộ điều khiển, phải không? Vì OP muốn có một trung tâm nhắn tin, điều này có thể không lý tưởng với anh ta. Nhưng cũng rất vui khi học được cách tiếp cận của bạn. Nó hữu ích trong nhiều trường hợp và như bạn đã nói, bản thân góc cạnh cũng sử dụng nó.
fasfsfgs

Tôi đang cố gắng làm theo một ví dụ được cung cấp bởi satchmorun. Tôi đang tạo một số html trong thời gian chạy, nhưng tôi không sử dụng mẫu của chỉ thị. Tôi đang sử dụng bộ điều khiển của chỉ thị để chỉ định một hàm để gọi từ html được thêm vào nhưng hàm không được gọi. Về cơ bản, tôi có chỉ thị này: directives.directive ('abcXyz', function ($ compile {return {limit: 'AE', Request: 'ngModel', controller: function ($ scope) {$ scope. Chức năng1 = function () {..};}, html của tôi là: "<a href="" ng-click="osystem1('itemtype')">
Đánh dấu

Đây là giải pháp thanh lịch duy nhất có thể hiển thị api chỉ thị nếu chỉ thị không phải là một singleton! Tôi vẫn không thích sử dụng $scope.$parent[alias]vì nó có mùi đối với tôi như sử dụng api góc bên trong. Nhưng vẫn không thể tìm thấy giải pháp thanh lịch hơn cho các chỉ thị not-singleton. Các biến thể khác như phát sự kiện hoặc xác định đối tượng trống trong bộ điều khiển mẹ để api chỉ thị có mùi nhiều hơn.
Ruslan Stelmachenko

3

Tôi có giải pháp tốt hơn nhiều.

đây là chỉ thị của tôi, tôi đã đưa vào tham chiếu đối tượng trong chỉ thị và đã mở rộng điều đó bằng cách thêm hàm gọi trong mã chỉ thị.

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

Khai báo chỉ thị trong HTML với một tham số:

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

Bộ điều khiển của tôi:

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

Điều này về cơ bản đi ngược lại với các nguyên tắc phân tách các mối quan tâm. Bạn cung cấp cho chỉ thị một đối tượng được khởi tạo trong bộ điều khiển và bạn ủy quyền trách nhiệm quản lý đối tượng đó (tức là tạo hàm gọi) cho chỉ thị. Theo tôi, KHÔNG phải là giải pháp tốt hơn.
Florin Vistig
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.