我有一个自定义指令,它使用一个属性来指定它修改的另一个控件。
指令定义对象:
{
restrict: 'E',
templateUrl: 'myTemplate.html',
scope: {
targetId: '@'
},
controller: MyController,
controllerAs: 'vm',
bindToController: true
}
指令控制器上的函数修改目标元素的内容(输入字段):
function onSelection (value) {
var $element = $('#' + vm.targetId);
$element.val('calculated stuff');
$element.trigger('input');
}
单元测试(Jasmine / Karma / PhantomJS)当前将元素附加到页面。这有效,但它看起来像是一种代码味道。
beforeEach(inject(function($rootScope, $compile) {
var elementHtml = '<my-directive target-id="bar"></my-directive>' +
'<input type="text" id="bar">';
scope = $rootScope.$new();
angularElement = angular.element(elementHtml);
angularElement.appendTo(document.body); // HELP ME KILL THIS!
element = $compile(angularElement)(scope);
scope.$digest();
}));
afterEach(function () {
angularElement.remove(); // HELP ME KILL THIS!
});
我尝试重写控制器函数以避免jQuery;这没有帮助。
如何修改指令或测试以消除appendTo / remove?
答案 0 :(得分:2)
最好的办法是将指令迁移到属性而不是元素。这消除了对target-id
属性的需要,您不需要寻找目标元素。
请参阅http://jsfiddle.net/morloch/621rp33L/
<强>指令强>
angular.module('testApp', [])
.directive('myDirective', function() {
var targetElement;
function MyController() {
var vm = this;
vm.onSelection = function() {
targetElement.val('calculated stuff');
targetElement.trigger('input');
}
}
return {
template: '<div></div>',
restrict: 'A',
scope: {
targetId: '@'
},
link: function postLink(scope, element, attrs) {
targetElement = element;
},
controller: MyController,
controllerAs: 'vm',
bindToController: true
};
});
<强>测试强>
describe('Directive: myDirective', function() {
// load the directive's module
beforeEach(module('testApp'));
var element, controller, scope;
beforeEach(inject(function($rootScope, $compile) {
scope = $rootScope.$new();
element = angular.element('<input my-directive type="text" id="bar">');
$compile(element)(scope);
scope.$digest();
controller = element.controller('myDirective');
}));
it('should have an empty val', inject(function() {
expect(element.val()).toBe('');
}));
it('should have a calculated val after select', inject(function() {
controller.onSelection();
expect(element.val()).toBe('calculated stuff');
}));
});
答案 1 :(得分:1)
这是另一个保持逻辑几乎完全相同的建议:使用第二个指令使控制器上的目标element
可用,然后您可以将其传递给主指令进行处理:http://jsfiddle.net/morloch/p8r2Lz1L/
<强> getElement 强>
.directive('getElement', function() {
return {
restrict: 'A',
scope: {
getElement: '='
},
link: function postLink(scope, element, attrs) {
scope.getElement = element;
}
};
})
<强> myDirective 强>
.directive('myDirective', function() {
function MyController() {
var vm = this;
vm.onSelection = function() {
vm.targetElement.val('calculated stuff');
vm.targetElement.trigger('input');
}
}
return {
template: '<div></div>',
restrict: 'E',
scope: {
targetElement: '='
},
controller: MyController,
controllerAs: 'vm',
bindToController: true
};
})
<强>测试强>
describe('Directive: myDirective', function() {
// load the directive's module
beforeEach(module('testApp'));
var element, controller, scope;
beforeEach(inject(function($rootScope, $compile) {
scope = $rootScope.$new();
element = angular.element('<input get-element="elementBar" type="text" id="bar"><my-directive target-element="elementBar"></my-directive>');
$compile(element)(scope);
scope.$digest();
controller = $(element[1]).controller('myDirective');
}));
it('should have an empty val', inject(function() {
expect($(element[0]).val()).toBe('');
}));
it('should have a calculated val after select', inject(function() {
controller.onSelection();
expect($(element[0]).val()).toBe('calculated stuff');
}));
});