我有以下指令:
!(function (window,angular) { 'use strict'; /** * @ngdoc directive * @name app.directive:social * @description * # social */ angular.module('app') .directive('social',function(social_network_conf) { return { restrict: 'A',scope: { social: "@" },require: 'ngModel',controller: function($scope,$element){ //for tests only $scope.render = function(){ //how to I get the ngModel here ngModel.$render(); }; $scope.setViewValue = function(val){ ngModel.$setViewValue(val); }; },link: function(scope,element,attr,ngModel) { ngModel.$formatters.push(function(value) {// from model to view value = value.trim(); if(value){ if (value.indexOf(social_network_conf.matcher) === 0){ var split_link = value.split(social_network_conf.divider); return split_link[split_link.length-1]; } else{ return value; } } }); ngModel.$parsers.push(function(value) { // from view to model value = value.trim(); if(value){ if (value.indexOf(social_network_conf.matcher) === 0){ return value; } else{ return social_network_conf.prefix + scope.social + social_network_conf.suffix + value; } } }); } }; }); }(window,window.angular));
测试如下:
'use strict'; describe('Directive: social',function () { // load the directive's module beforeEach(module('app')); var element,social_network_conf,linker,scope,$httpBackend; beforeEach(inject(function ($rootScope,_$httpBackend_,_social_network_conf_) { scope = $rootScope.$new(); social_network_conf = _social_network_conf_; //Must be an object to make use of prototypical inheritence for out-side-of-isolate-scope access scope.models = {}; $httpBackend = _$httpBackend_; $httpBackend.whenGET(/views\/social.html/).respond('<div></div>'); $httpBackend.whenGET(/views\/navigation.html/).respond('<div></div>'); })); it('It should convert ngModel into full HTTP address notation',inject(function ($compile) { element = angular.element('<input social="test_network" ng-model="models.test_network"></social>'); linker = $compile(element); element = linker(scope); scope.$apply(function(){ element.val('test'); }); scope.$digest(); expect(scope.models.test_network).toBe(social_network_conf.prefix + 'test' + social_network_conf.suffix); // expect(element.text()).toBe('this is the social directive'); })); });
问题是这些行:
scope.$apply(function(){ element.val('test'); });
实际上并没有调用我定义的$解析器.
虽然使用API创建一个控制器来调用ngModel $render或ngModel $setViewValue,但是我无法访问指令控制器上的ngModel,而没有一个丑陋的黑客.
2可能的解决方案:
首先是将元素包含在表单中,并分配输入字段和表单的name属性,然后访问输入字段如下:
scope.form_name.input_name.$setViewValue('value')
工作代码:
'use strict'; describe('Directive: social',$compile,$body,html,_$compile_,_social_network_conf_) { scope = $rootScope.$new(); social_network_conf = _social_network_conf_; //Must be an object to make use of prototypical inheritence for out-side-of-isolate-scope access scope.models = {}; $compile = _$compile_; $httpBackend = _$httpBackend_; $body = $('body'); $httpBackend.whenGET(/views\/social.html/).respond('<div></div>'); $httpBackend.whenGET(/views\/navigation.html/).respond('<div></div>'); $body.empty(); html = '<form name="testForm">' + '<input social="test_network" name="test" ng-model="models.test_network">' + '</form>'; })); it('It should convert ngModel into full HTTP address notation',function () { element = angular.element(html); linker = $compile(element); element = linker(scope); var viewValue = 'test',input = element.find('input'); scope.models.test_network = viewValue; scope.$digest(); scope.testForm.test.$setViewValue(viewValue); scope.$digest(); expect(scope.models.test_network).toBe(social_network_conf.prefix + input.isolateScope().social + social_network_conf.suffix + viewValue); });
或者,第二个提供在元素上发送输入事件 – 对于我来说,它不适用于角度1.3.
这在This YouTube video展示.
element.val('test'); element.trigger('input');