[英]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));
我努力使它起作用,但是基本上jqLite方法實際上是在進行angular.element()
調用。 除非您執行var slice = [].slice;
否則slice方法將var slice = [].slice;
這是我在服務頂部所做的。
我希望這可以幫助其他人:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.