如何从AngularJs中的自定义指令调用控制器方法

时间:2016-05-12 13:55:55

标签: angularjs angular2-directives

UI

    <div class="row" ng-app="myModule" ng-controller="multiselect">
        <div  class="col-md-2">
            <div id="lob" ng-dropdown-multiselect="" extra-settings="dropdownSetting" options="lobs" attrfilterprojectsonlob="getProjects"
                 selected-model="lobsSelected" checkboxes="true">
            </div>
        </div>

        <div  class="col-md-2">
            <div id="projects" ng-dropdown-multiselect="" extra-settings="dropdownSetting" options="projects"
                 selected-model="projectsSelected" checkboxes="true">
            </div>
        </div>
    </div>

角度控制器

    var myApp = angular.module('myModule', ['angularjs-dropdown-multiselect']);
    myApp.controller('multiselect', ['$scope', '$http', function ($scope, $http) {
        $scope.lobsSelected = [];
        $scope.lobs = [];
        $scope.projectsSelected = [];
        $scope.projects = [];
        $scope.dropdownSetting = {
            scrollable: true,
            scrollableHeight: '200px'
        }


        $http.get('Home/GetALLLOB').then(function (data) {
            angular.forEach(data.data, function (value, index) {
                $scope.lobs.push({ id: value.N_LevelID, label: value.T_LevelName }
                );
            });
        })


        $http.get('Home/GetAllProjects').then(function (data) {
            debugger;
            angular.forEach(data.data, function (value, index) {
                $scope.projects.push({ id: value.N_LevelID, label: value.T_LevelName }
                );
            });
        })


        $scope.getProjects = function (selectedId) {
            debugger;
            var parentId = id;
            $http.get('Home/GetAllProjects', { params: { "parentId": selectedId } })
                .then(function (data) {
                angular.forEach(data.data, function (value, index) {
                    debugger;
                    $scope.projects.push({ id: value.N_LevelID, label: value.T_LevelName }
                    );
                });
                })
            .catch(function (data) {
                console.error('Gists error', data.status, data.data);
            })
        }

    }])

指令: - 请忽略fn_template()

'use strict';

var directiveModule = angular.module('angularjs-dropdown-multiselect', []);



directiveModule.directive('ngDropdownMultiselect', ['$filter', '$document', '$compile', '$parse',
    function ($filter, $document, $compile, $parse) {

        return {
            //restrict: 'AE',
            restrict: 'AEC',
            scope: {
                selectedModel: '=',
                options: '=',
                extraSettings: '=',
                events: '=',
                searchFilter: '=?',
                translationTexts: '=',
                groupBy: '@',
                fn_selectAll: '&',
                selectedId :'=',
                attrfilterProjectsonLob: '&'
            },

            template: fn_Template,
            link: function ($scope, $element, $attrs) {

                var $dropdownTrigger = $element.children()[0];

                $scope.toggleDropdown = function () {
                    $scope.open = !$scope.open;
                };

                $scope.checkboxClick = function ($event, id) {
                    $scope.setSelectedItem(id);
                    $event.stopImmediatePropagation();
                };

                $scope.filterProjectsonLob = function ($event, id) {
                    debugger;
                    $scope.selectedId = id;
                    $scope.attrfilterProjectsonLob({value : selectedId});
                }


                $scope.externalEvents = {
                    onItemSelect: angular.noop,
                    onItemDeselect: angular.noop,
                    onSelectAll: angular.noop,
                    onDeselectAll: angular.noop,
                    onInitDone: angular.noop,
                    onMaxSelectionReached: angular.noop
                };

                $scope.settings = {
                    dynamicTitle: true,
                    scrollable: false,
                    scrollableHeight: '300px',
                    closeOnBlur: true,
                    displayProp: 'label',
                    idProp: 'id',
                    externalIdProp: 'id',
                    enableSearch: false,
                    selectionLimit: 0,
                    showCheckAll: true,
                    showUncheckAll: true,
                    closeOnSelect: false,
                    buttonClasses: 'btn btn-default',
                    closeOnDeselect: false,
                    groupBy: $attrs.groupBy || undefined,
                    groupByTextProvider: null,
                    smartButtonMaxItems: 0,
                    smartButtonTextConverter: angular.noop
                };

                $scope.texts = {
                    checkAll: 'Check All',
                    uncheckAll: 'Uncheck All',
                    selectionCount: 'checked',
                    selectionOf: '/',
                    searchPlaceholder: 'Search...',
                    buttonDefaultText: 'LOB',
                    dynamicButtonTextSuffix: 'Selected',
                    LOBSelected: ''
                };

                $scope.searchFilter = $scope.searchFilter || '';

                if (angular.isDefined($scope.settings.groupBy)) {
                    $scope.$watch('options', function (newValue) {
                        if (angular.isDefined(newValue)) {
                            $scope.orderedItems = $filter('orderBy')(newValue, $scope.settings.groupBy);
                        }
                    });
                }

                angular.extend($scope.settings, $scope.extraSettings || []);
                angular.extend($scope.externalEvents, $scope.events || []);
                angular.extend($scope.texts, $scope.translationTexts);

                $scope.singleSelection = $scope.settings.selectionLimit === 1;

                function getFindObj(id) {
                    var findObj = {};

                    if ($scope.settings.externalIdProp === '') {
                        findObj[$scope.settings.idProp] = id;
                    } else {
                        findObj[$scope.settings.externalIdProp] = id;
                    }

                    return findObj;
                }

                function clearObject(object) {
                    for (var prop in object) {
                        delete object[prop];
                    }
                }

                if ($scope.singleSelection) {
                    if (angular.isArray($scope.selectedModel) && $scope.selectedModel.length === 0) {
                        clearObject($scope.selectedModel);
                    }
                }

                if ($scope.settings.closeOnBlur) {
                    $document.on('click', function (e) {
                        var target = e.target.parentElement;
                        var parentFound = false;

                        while (angular.isDefined(target) && target !== null && !parentFound) {
                            if (_.contains(target.className.split(' '), 'multiselect-parent') && !parentFound) {
                                if (target === $dropdownTrigger) {
                                    parentFound = true;
                                }
                            }
                            target = target.parentElement;
                        }

                        if (!parentFound) {
                            $scope.$apply(function () {
                                $scope.open = false;
                            });
                        }
                    });
                }

                $scope.getGroupTitle = function (groupValue) {
                    if ($scope.settings.groupByTextProvider !== null) {
                        return $scope.settings.groupByTextProvider(groupValue);
                    }

                    return groupValue;
                };

                $scope.getButtonText = function () {

                    if ($scope.settings.dynamicTitle && ($scope.selectedModel.length > 0 || (angular.isObject($scope.selectedModel) && _.keys($scope.selectedModel).length > 0))) {

                        //if ($scope.settings.smartButtonMaxItems > 0) {

                        if ($scope.settings.smartButtonMaxItems >= 0) {


                            var itemsText = [];
                            var SelectedTexts = [];

                            angular.forEach($scope.options, function (optionItem) {

                                if ($scope.isChecked($scope.getPropertyForObject(optionItem, $scope.settings.idProp))) {
                                    var displayText = $scope.getPropertyForObject(optionItem, $scope.settings.displayProp);

                                    $scope.SelectedTexts = displayText;
                                    var converterResponse = $scope.settings.smartButtonTextConverter(displayText, optionItem);

                                    itemsText.push(converterResponse ? converterResponse : displayText);
                                }
                            });

                            //if ($scope.selectedModel.length > $scope.settings.smartButtonMaxItems) {
                            //    itemsText = itemsText.slice(0, $scope.settings.smartButtonMaxItems);
                            //    itemsText.push('...');
                            //}

                            if (itemsText.length <= 2) {
                                return itemsText.join(', ');
                            }

                            else {
                                var totalSelected;

                                if ($scope.singleSelection) {
                                    totalSelected = ($scope.selectedModel !== null && angular.isDefined($scope.selectedModel[$scope.settings.idProp])) ? 1 : 0;
                                } else {
                                    totalSelected = angular.isDefined($scope.selectedModel) ? $scope.selectedModel.length : 0;
                                }

                                if (totalSelected === 0) {
                                    return $scope.texts.buttonDefaultText;
                                } else {


                                    return totalSelected + ' ' + $scope.texts.buttonDefaultText + ' ' + $scope.texts.dynamicButtonTextSuffix;

                                }
                            }

                        }
                    } else {
                        return $scope.texts.buttonDefaultText;
                    }
                };

                $scope.getPropertyForObject = function (object, property) {
                    if (angular.isDefined(object) && object.hasOwnProperty(property)) {
                        return object[property];
                    }

                    return '';
                };

                $scope.selectAll = function () {

                    $scope.deselectAll(false);
                    $scope.externalEvents.onSelectAll();

                    angular.forEach($scope.options, function (value) {
                        $scope.setSelectedItem(value[$scope.settings.idProp], true);
                    });
                };

                $scope.deselectAll = function (sendEvent) {
                    sendEvent = sendEvent || true;

                    if (sendEvent) {
                        $scope.externalEvents.onDeselectAll();
                    }

                    if ($scope.singleSelection) {
                        clearObject($scope.selectedModel);
                    } else {
                        $scope.selectedModel.splice(0, $scope.selectedModel.length);
                    }
                };

                $scope.setSelectedItem = function (id, dontRemove) {
                    debugger;
                    var findObj = getFindObj(id);
                    var finalObj = null;

                    if ($scope.settings.externalIdProp === '') {
                        finalObj = _.find($scope.options, findObj);
                    } else {
                        finalObj = findObj;
                    }

                    if ($scope.singleSelection) {

                        clearObject($scope.selectedModel);
                        angular.extend($scope.selectedModel, finalObj);
                        $scope.externalEvents.onItemSelect(finalObj);
                        if ($scope.settings.closeOnSelect) $scope.open = false;

                        return;
                    }

                    dontRemove = dontRemove || false;

                    var exists = _.findIndex($scope.selectedModel, findObj) !== -1;



                    if (!dontRemove && exists) {
                        $scope.selectedModel.splice(_.findIndex($scope.selectedModel, findObj), 1);
                        $scope.externalEvents.onItemDeselect(findObj);
                    } else if (!exists && ($scope.settings.selectionLimit === 0 || $scope.selectedModel.length < $scope.settings.selectionLimit)) {
                        $scope.selectedModel.push(finalObj);
                        $scope.externalEvents.onItemSelect(finalObj);
                    }
                    if ($scope.settings.closeOnSelect) $scope.open = false;
                };

                $scope.isChecked = function (id) {
                    if ($scope.singleSelection) {
                        return $scope.selectedModel !== null && angular.isDefined($scope.selectedModel[$scope.settings.idProp]) && $scope.selectedModel[$scope.settings.idProp] === getFindObj(id)[$scope.settings.idProp];
                    }
                    return _.findIndex($scope.selectedModel, getFindObj(id)) !== -1;
                };

                $scope.externalEvents.onInitDone();
            }
        };
    }]);

function fn_Template(element, attrs) {
    var checkboxes = attrs.checkboxes ? true : false;
    var groups = attrs.groupBy ? true : false;


    var template = '<div class="multiselect-parent btn-group dropdown-multiselect">';
    template += '<button type="button" class="dropdown-toggle" ng-class="settings.buttonClasses" ng-click="toggleDropdown()">{{getButtonText()}}&nbsp;<span class="caret"></span></button>';
    template += '<ul class="dropdown-menu dropdown-menu-form" ng-style="{display: open ? \'block\' : \'none\', height : settings.scrollable ? settings.scrollableHeight : \'auto\' }" style="overflow: scroll" >';
    template += '<li ng-hide="!settings.showCheckAll || settings.selectionLimit > 0"><a data-ng-click="selectAll()"><span class="glyphicon glyphicon-ok"></span>  {{texts.checkAll}}</a>';
    template += '<li ng-show="settings.showUncheckAll"><a data-ng-click="deselectAll();"><span class="glyphicon glyphicon-remove"></span>   {{texts.uncheckAll}}</a></li>';
    template += '<li ng-hide="(!settings.showCheckAll || settings.selectionLimit > 0) && !settings.showUncheckAll" class="divider"></li>';
    template += '<li ng-show="settings.enableSearch"><div class="dropdown-header"><input type="text" class="form-control" style="width: 100%;" ng-model="searchFilter" placeholder="{{texts.searchPlaceholder}}" /></li>';
    template += '<li ng-show="settings.enableSearch" class="divider"></li>';

    if (groups) {
        template += '<li ng-repeat-start="option in orderedItems | filter: searchFilter" ng-show="getPropertyForObject(option, settings.groupBy) !== getPropertyForObject(orderedItems[$index - 1], settings.groupBy)" role="presentation" class="dropdown-header">{{ getGroupTitle(getPropertyForObject(option, settings.groupBy)) }}</li>';
        template += '<li ng-repeat-end role="presentation">';
    } else {
        template += '<li role="presentation" ng-repeat="option in options | filter: searchFilter">';
    }


    template += '<a role="menuitem" tabindex="-1" ng-click="setSelectedItem(getPropertyForObject(option,settings.idProp))">';

    if (checkboxes) {
        template += '<div class="checkbox"><label><input class="checkboxInput" type="checkbox" ng-click="checkboxClick($event, getPropertyForObject(option,settings.idProp));  filterProjectsonLob($event, getPropertyForObject(option,settings.idProp)) "ng-checked="isChecked(getPropertyForObject(option,settings.idProp))" /> {{getPropertyForObject(option, settings.displayProp)}}</label></div></a>';
    } else {
        template += '<span data-ng-class="{\'glyphicon glyphicon-ok\': isChecked(getPropertyForObject(option,settings.idProp))}"></span> {{getPropertyForObject(option, settings.displayProp)}}</a>';
    }

    template += '</li>';

    template += '<li class="divider" ng-show="settings.selectionLimit > 1"></li>';
    template += '<li role="presentation" ng-show="settings.selectionLimit > 1"><a role="menuitem">{{selectedModel.length}} {{texts.selectionOf}} {{settings.selectionLimit}} {{texts.selectionCount}}</a></li>';

    template += '</ul>';
    template += '</div>';

    element.html(template);
}

评论 ----------。 请指导我正在做什么,因为控制器方法没有被调用。 我需要在$ scope.filterProjectsonLob指令中调用控制器中存在的$ scope.getProjects方法。请指导我,因为我是angularJs的新手。

2 个答案:

答案 0 :(得分:0)

您的指令可以拥有它自己的控制器:

angular.directive(function() { //blah blah
  return {
    //restrict: 'AE',
    restrict: 'AEC',
    scope: {
    },
    controller: multiselect,
    controllerAs: 'vm'
  }
});

然后就像你通常那样,这是vm.methodNameCall(arguments)的问题。

答案 1 :(得分:0)

这里发生的是您的控制器存在于指令的父作用域中,并且该指令具有隔离范围,因此它不会看到其父作用域的数据。

最简单的解决方案(但不一定最正确)是在指令中使用$scope.$parent$scope.$parent.getProjects)来访问控制器的范围。

更正确的解决方案是将您的multiselect控制器重构为指令。使用multiselect作为指令(例如ngMultiselect),您可以将其控制器注入其他指令。您不需要更改控制器代码,只需将其作为控制器指示而不是使用ng-controller

步骤1:用ngMultiselect指令替换ng-controller。

directiveModule.directive('ngMultiselect', function(){
    return {
        restrict: 'AEC',
        controller: 'multiselect'
    };
});

<div class="row" ng-app="myModule" ng-multiselect> ... </div>

第2步:更新multiselect控制器以公开getProjects功能

// change:
$scope.getProjects = function (selectedId) {...};

// to:
this.getProjects = function (selectedId) {...};

// and if you still need getProjects on multiselect's scope, you can add $scope.getProjects = this.getProjects;

步骤3:通过要求ngDropdownMultiselect

将控制器注入ngMultiselect
directiveModule.directive('ngDropdownMultiselect', ['$filter', '$document', '$compile', '$parse',
    function ($filter, $document, $compile, $parse) {

        return {
            //restrict: 'AE',
            restrict: 'AEC',
            require: 'ngMultiselect',
            scope: {
                selectedModel: '=',
                options: '=',
                // etc ...
            },

            template: fn_Template,
            link: function ($scope, $element, $attrs, MultiselectCtrl) {
                $scope.getProjects = MultiselectCtrl.getProjects;

                // and the rest of your stuff here...
            }
        };
    }
]);

学习如何设置和区分控制器+指令链接功能无疑是学习角度的更好点之一。我会说除了简单的组件之外还需要构建任何东西。有很多关于它的教程,但是直到你在自己的编码中遇到它才真的很难理解。

编辑: 只是想要注意,您需要查看定义指令和控制器的模块,并相应地设置模块依赖性。