为什么我的自定义指令下拉列表没有触发?

时间:2015-04-30 20:28:55

标签: angularjs drop-down-menu angularjs-directive angular-ui-bootstrap

发生了什么?

从我所知道的一切都能正常运行和填充。唯一不正确的是下拉。出于某种原因,它不会触发并显示所有子菜单/分隔符。

app.directives.js

angular.module('mb.essentials', [])
.directive('mbAttribute', function ($log) {
    return {
        restrict: 'A',
        scope: {
            mbAttribute: '='
        },
        link: function(scope, element, attrs) {
            if (angular.isUndefined(scope.mbAttribute)) {
                $log.error(
                    'You must specify at least one attribute, condition pair!\n' +
                    'Eg. mb-attribute="{\'alert-warning\': alert.alertType}"');
            }

            $.each(scope.mbAttribute, function (key, value) {
                scope.$watch(function () {
                    return value;
                },
                function() {
                    if (value) {
                        element.attr(key, '');
                    } else {
                        element.removeAttr(key, '');
                    }
                });
            });
        }
    };
})
.directive('mbNavbar', function () {
    return {
        restrict: 'AE',
        require: '^dropdown',
        transclude: true,
        scope: {
            brand: '=',
            menus: '=',
            affixed: '=',
            inverse: '=',
            search: '=',
            searchFn: '&',
            navFn: '&'
        },
        controller: function ($scope, $element, $attrs, $sce) {
            $scope.isCollapsed = true;

            $scope.defaults = {
                brand: '<span class="glyphicon glyphicon-certificate"></span>',
                menus: [],
                search: {
                  show: false
                }
            }; // end defaults

            if (angular.isUndefined($attrs.navFn)) {
                $scope.navfn = function (action) {
                    if (angular.isObject(action))
                        $scope.$emit('nav.menu', action);
                    else
                        $scope.$emit('nav.menu', {'action': action});
                }
            };

            if (angular.isUndefined($attrs.searchFn)) {
                $scope.searchFn = function () {
                    $scope.$emit('nav.search.execute');
                }
            };

            $scope.trustedBrand = angular.isDefined($attrs.brand) ? $sce.trustAsHtml($scope.brand) : $sce.trustAsHtml($scope.defaults.brand);
            $scope.hasMenus = function () {
                return angular.isDefined($scope.menus);
            };

            $scope.hasDropdownMenu = function (menu) {
                return (angular.isDefined(menu.menu) && angular.isArray(menu.menu));
            };

            $scope.isDivider = function (item) {
                return (angular.isDefined(item.divider) && angular.equals(item.divider, true));
            }

            $scope.navAction = function (action) {
                $scope.navFn({'action': action});
            };
        },
        template: 
        '<nav class="navbar" ng-class="{\'navbar-inverse\': inverse,\'navbar-default\': !inverse,\'navbar-fixed-top\': affixed == \'top\',\'navbar-fixed-bottom\': affixed == \'bottom\'}" role="navigation">' +
            '<div class="container-fluid">' +
                '<div class="navbar-header">' +
                    '<button type="button" class="navbar-toggle" ng-click="isCollapsed = !isCollapsed">' +
                        '<span class="sr-only">Toggle Navigation</span>' +
                        '<span class="icon-bar"></span>' +
                        '<span class="icon-bar"></span>' +
                        '<span class="icon-bar"></span>' +
                    '</button>' +
                    '<a class="navbar-brand" ng-bind-html="trustedBrand"></a>' +
                '</div>' +
                '<div collapse="isCollapsed" class="collapse navbar-collapse">' +
                    '<ul class="nav navbar-nav" ng-if="hasMenus()">' +
                        '<li ng-repeat="menu in menus" mb-attribute="{\'dropdown\': hasDropdownMenu(menu)}">' +
                            '<a ng-if="!hasDropdownMenu(menu)" ng-click="navAction(menu.action)">{{menu.title}}</a>' +
                            '<a ng-if="hasDropdownMenu(menu)" class="dropdown-toggle" dropdown-toggle>' +
                                '{{menu.title}} <b class="caret"></b>' +
                            '</a>' +
                            '<ul ng-if="hasDropdownMenu(menu)" class="dropdown-menu">' +
                                '<li ng-repeat="item in menu.menu" ng-class="{\'nav-divider\': isDivider(item)}">' +
                                    '<a ng-if="!isDivider(item)" ng-click="navAction(item.action)">{{item.title}}</a>' +
                                '</li>' +
                            '</ul>' +
                        '</li>' +
                    '</ul>' +
                    '<form ng-if="search.show" class="navbar-form navbar-right" role="search">' +
                        '<div class="form-group">' +
                            '<div class="input-group">' +
                                '<input type="text" class="form-control" placeholder="Search" ng-model="search.terms" />' +
                                '<span class="input-group-btn">' +
                                    '<button class="btn btn-default" type="button">' +
                                        '<span class="glyphicon glyphicon-search"></span>' +
                                    '</button>' +
                                '</span>' +
                            '</div>' +
                        '</div>' +
                    '</form>' +
                '</div>' +
            '</div>' +
        '</nav>'
    };
});

Plnkr

1 个答案:

答案 0 :(得分:1)

问题

基本上,angular会编译DOM,然后mb-attribute指令会添加下拉指令。基本上Angular和UI Bootstrap都不知道该指令是否存在。

&#34;解决方案&#34;

我把它放在引号中,因为它不完全是一个解决方案。

而不是有条件地检查是否应该添加下拉指令。我们只需将它添加到每个元素,无论它是否为下拉菜单。

这种情况在这种情况下有效的原因是因为UI Bootstraps下拉指令要求它与下拉菜单和下拉菜单配对才能正常运行。

<强> angular.directives.js

angular.module('mb.essentials', [])
.directive('mbNavbar', function () {
    return {
        restrict: 'AE',
        require: '^dropdown',
        scope: {
            brand: '=',
            menus: '=',
            affixed: '=',
            inverse: '=',
            search: '=',
            searchFn: '&',
            navFn: '&'
        },
        controller: function ($scope, $element, $attrs, $sce) {
            $scope.isCollapsed = true;

            $scope.defaults = {
                brand: '<span class="glyphicon glyphicon-certificate"></span>',
                menus: [],
                search: {
                  show: false
                }
            } // end defaults

            if (angular.isUndefined($attrs.navFn)) {
                $scope.navfn = function (action) {
                    if (angular.isObject(action))
                        $scope.$emit('nav.menu', action);
                    else
                        $scope.$emit('nav.menu', {'action': action});
                }
            }

            if (angular.isUndefined($attrs.searchFn)) {
                $scope.searchFn = function () {
                    $scope.$emit('nav.search.execute');
                }
            }

            $scope.trustedBrand = angular.isDefined($attrs.brand) ? $sce.trustAsHtml($scope.brand) : $sce.trustAsHtml($scope.defaults.brand);
            $scope.hasMenus = function () {
                return angular.isDefined($scope.menus);
            }

            $scope.hasDropdownMenu = function (menu) {
                return (angular.isDefined(menu.menu) && angular.isArray(menu.menu));
            }

            $scope.isDivider = function (item) {
                return (angular.isDefined(item.divider) && angular.equals(item.divider, true));
            }

            $scope.navAction = function (action) {
                $scope.navFn({'action': action});
            }
        },
        template: 
        '<nav class="navbar" ng-class="{\'navbar-inverse\': inverse,\'navbar-default\': !inverse,\'navbar-fixed-top\': affixed == \'top\',\'navbar-fixed-bottom\': affixed == \'bottom\'}" role="navigation">' +
            '<div class="container-fluid">' +
                '<div class="navbar-header">' +
                    '<button type="button" class="navbar-toggle" ng-click="isCollapsed = !isCollapsed">' +
                        '<span class="sr-only">Toggle Navigation</span>' +
                        '<span class="icon-bar"></span>' +
                        '<span class="icon-bar"></span>' +
                        '<span class="icon-bar"></span>' +
                    '</button>' +
                    '<a class="navbar-brand" ng-bind-html="trustedBrand"></a>' +
                '</div>' +
                '<div collapse="isCollapsed" class="collapse navbar-collapse">' +
                    '<ul class="nav navbar-nav" ng-if="hasMenus()">' +
                        '<li ng-repeat="menu in menus" dropdown>' +
                            '<a ng-if="!hasDropdownMenu(menu)" ng-click="navAction(menu.action)">{{menu.title}}</a>' +
                            '<a ng-if="hasDropdownMenu(menu)" class="dropdown-toggle" dropdown-toggle>' +
                                '{{menu.title}} <b class="caret"></b>' +
                            '</a>' +
                            '<ul ng-if="hasDropdownMenu(menu)" class="dropdown-menu">' +
                                '<li ng-repeat="item in menu.menu" ng-class="{\'nav-divider\': isDivider(item)}">' +
                                    '<a ng-if="!isDivider(item)" ng-click="navAction(item.action)">{{item.title}}</a>' +
                                '</li>' +
                            '</ul>' +
                        '</li>' +
                    '</ul>' +
                    '<form ng-if="search.show" class="navbar-form navbar-right" role="search">' +
                        '<div class="form-group">' +
                            '<div class="input-group">' +
                                '<input type="text" class="form-control" placeholder="Search" ng-model="search.terms" />' +
                                '<span class="input-group-btn">' +
                                    '<button class="btn btn-default" type="button">' +
                                        '<span class="glyphicon glyphicon-search"></span>' +
                                    '</button>' +
                                '</span>' +
                            '</div>' +
                        '</div>' +
                    '</form>' +
                '</div>' +
            '</div>' +
        '</nav>'
    };
});

Plnkr

面向未来

我将使用此解决方案,但我不打算将其标记为解决方案。我想如果将来有人想出一个真正的解决方案,那么我可以将其标记为。