簡體   English   中英

自定義ng-if指令angularjs

[英]custom ng-if directive angularjs

我正在嘗試創建一個類似於ng-if指令的指令,所以我想抓住它的功能。 我創建了這樣的指令:

(function () {
    'use strict';

    angular.module('sapphire.directives').directive('ifScreensize', directive);

    function directive(ngIfDirective, $window) {
        var ngIf = ngIfDirective[0];

        return {
            controller: 'IfScreensizeController',
            prority: 1,
            scope: {
                options: '=ifScreensize'
            },
            link: function (scope, element, attrs, controller) {
                scope.$watch('options', function (options) {
                    controller.handle(element, options, ngIf);
                });

                var window = angular.element($window)
                window.bind('resize', function () {
                    $timeout(function () {
                        controller.handle(element, scope.options, ngIf);
                    }, 500);
                });
            }
        };
    };
})();

然后控制器看起來像這樣:

(function () {
    'use strict';

    angular.module('sapphire.directives').controller('IfScreensizeController', controller);

    function controller(ifScreensizeService) {
        this.handle = ifScreensizeService.handle;
    };
})();

最后,該服務如下所示:

(function () {
    'use strict';

    angular.module('sapphire.directives').service('ifScreensizeService', service);

    function service($window) {
        return {
            handle: handle
        };

        //////////////////////////////////////////////////

        function handle(element, options, ngIf) {
            var window = angular.element($window),
                width = $window.innerWidth,
                value = true;

            switch (options.operator) {
                case '>':
                    value = options.width >= width;
                    break;
                case '>=':
                    value = options.width > width;
                    break;
                case '<':
                    value = options.width < width;
                    break;
                case '<=':
                    value = options.width <= width;
                    break;
                default:
                    break;
            }

            ngIf.link.apply(ngIf, value);
        };
    };
})();

問題是,當我嘗試使用指令時,出現錯誤:

TypeError:在非對象上調用CreateListFromArrayLike

哪個在ngIf.link.apply(ngIf, value); 線。 有人可以告訴我我需要做什么才能使指令生效嗎?

.apply需要一個數組。 嘗試以這種方式調用ngIf.link.apply(ngIf, [value]);

好的,所以我使用了實際的ng-if指令代碼來創建我的指令。 因此,我將指令更改為:

angular.module('sapphire.directives').directive('ifScreensize', directive);

function directive($timeout, $window) {
    return {
        controller: 'IfScreensizeController',
        multiElement: true,
        transclude: 'element',
        priority: 600,
        terminal: true,
        restrict: 'A',
        $$tlb: true,
        bindToController: {
            options: '=ifScreensize'
        },
        link: function (scope, element, attrs, controller, transclude) {
            scope.$watch('options', function (options) {
                controller.handle(element, attrs, transclude);
            });

            var window = angular.element($window)
            window.bind('resize', function () {
                $timeout(function () {
                    controller.handle(element, attrs, transclude);
                }, 500);
            });
        }
    };
};

然后我將控制器更改為模仿ng-if指令,如下所示:

angular.module('sapphire.directives').controller('IfScreensizeController', controller);

function controller($animate, $compile, ifScreensizeService) {
    var self = this;        
    var block, childScope, previousElements;

    self.handle = function handle($element, $attr, $transclude) {
        var value = ifScreensizeService.evaulate(self.options);

        console.log(value);

        if (value) {
            if (!childScope) {
            $transclude(function(clone, newScope) {
                childScope = newScope;
                clone[clone.length++] = $compile.$$createComment('end ngIf', $attr.ngIf);
                // Note: We only need the first/last node of the cloned nodes.
                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
                // by a directive with templateUrl when its template arrives.
                block = {
                clone: clone
                };
                $animate.enter(clone, $element.parent(), $element);
            });
            }
        } else {
            if (previousElements) {
                console.log(previousElements);
                previousElements.remove();
                previousElements = null;
            }
            if (childScope) {
                childScope.$destroy();
                childScope = null;
            }
            if (block) {
                previousElements = ifScreensizeService.getBlockNodes(block.clone);
                $animate.leave(previousElements).done(function(response) {
                    if (response !== false) previousElements = null;
                });
                block = null;
            }
        }
    };
};

那里的大部分代碼都可以在ng-if指令中找到。 我只是對其進行了少許修改以與我的指令一起使用。 需要注意的一件事是,在原始的ng-if指令中,它調用了我們無權訪問的getBlockNodes ,因此我將其添加到了服務中:

angular.module('sapphire.directives').service('ifScreensizeService', service);

function service($window) {
    var slice = [].slice;
    return {
        evaulate: evaulate,
        getBlockNodes: getBlockNodes
    };

    //////////////////////////////////////////////////

    function evaulate(options) {
        var window = angular.element($window),
            width = $window.innerWidth,
            value = true;

        switch (options.operator) {
            case '>':
                value = width >= options.width;
                break;
            case '>=':
                value = width > options.width;
                break;
            case '<':
                value = width < options.width;
                break;
            case '<=':
                value = width <= options.width;
                break;
            default:
                break;
        }

        console.log(options, width, value);

        return value;
    };

    function getBlockNodes(nodes) {
        // TODO(perf): update `nodes` instead of creating a new object?
        var node = nodes[0];
        var endNode = nodes[nodes.length - 1];
        var blockNodes;

        for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
            if (blockNodes || nodes[i] !== node) {
                if (!blockNodes) {
                    console.log(nodes);
                    blockNodes = angular.element(slice.call(nodes, 0, i));
                }
                blockNodes.push(node);
            }
        }

        return blockNodes || nodes;
    };
};

最后的警告是這一行:

blockNodes = angular.element(slice.call(nodes, 0, i));

在原始的ng-if中 ,實際上是:

blockNodes = jqLite(slice.call(nodes, 0, i));

我努力使它起作用,但是基本上jqLit​​e方法實際上是在進行angular.element()調用。 除非您執行var slice = [].slice;否則slice方法將var slice = [].slice; 這是我在服務頂部所做的。

我希望這可以幫助其他人:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM