我有两个元素,看起来会更像:
<chart type="type-one" legend="true"></chart>
<chart type="type-two" legend="true"></chart>
每个元素都应该由它自己的指令处理,放在一个单独的文件中。
如何使这些指令查找要处理的元素名称chart
和type
属性?
更新: @vittore,感谢您的答疑!我的问题是我希望有不同类型的图表,这些图表由来自不同文件的指令处理,导致没有一个巨型文件处理chart
元素,其中内部函数针对每种类型的图表运行,而是更多模块化文件负责处理每种图表类型。
现在我这样做:
app.directive('chart', function () {
return {
restrict: 'E',
require: 'ngModel',
scope: {
'ngModel': '=',
'showGrouped': '='
},
link: function (scope, element, attrs, ctrl) {
if (attrs.type != 'type-one') {return}
render()
}
}
});
所以我检查了type属性,如果它不是某个值,则返回,否则运行相应的渲染代码。我在每个指令文件中都有这段代码来执行特定的图表类型渲染。我确信这种方法有问题。
请指教!
答案 0 :(得分:4)
使用范围参数
angular.module('myModule',[])
.directive('chart', function() {
return {
templateUrl:'chart.html',
replace:true,
restrict: 'E',
scope: {
type:'=',
legend:'='
}
}
})
和chart.html
<div> {{type}} {{legend}} </div>
<强>更新强>
为了真正需要属性,当提供无效值或根本没有提供某些值时,您可以从指令的link
或compile
函数抛出异常。
更新2:
属性范围绑定有3种类型:=
,&
,@
。你应该适当地使用它们。
如果您只想将字符串传递给指令,可以使用@
绑定:
.directive('chart', function() {
return {
templateUrl:'chart.html',
replace:true,
restrict: 'E',
scope: {
type:'@',
legend:'@'
}
}
})
这样您的参数将被视为字符串:
scope.type='true'
scope.legend='type-one'
或者您可能希望将它们绑定到范围字段:
<chart type="myModel.type" legend="myModel.legend" />
拥有=
范围声明:
.directive('chart', function() {
return {
templateUrl:'chart.html',
replace:true,
restrict: 'E',
scope: {
type:'=',
legend:'='
}
}
})
将在指令的scope
属性和父scope
属性之间创建双向绑定:
scope.type = $parent.myModel.type
scope.legend = $parent.myModel.legend
之后,您可以更改父作用域和指令作用域中的两个属性。
最复杂的&
绑定,它允许您提供带有父范围参数的方法,以便从指令调用:
app.directive("chart", function() {
return {
scope: {
details: "&"
},
template: '<input type="text" ng-model="value">' +
'<div class="button" ng-click="details({legend:value})">Show Details</div>'
}
})
和标记
<chart details='showDetails(legend)'></chart>
有关每种范围绑定的详细信息,请参阅egghead.io的优秀视频:
答案 1 :(得分:1)
我使用以下内容:
注册应用
var app = angular.module('app', []);
注册常量以控制我们支持的类型
app.constant('chartTypes', ['typeOne', 'typeTwo']);
指令
app.directive('chart', ['$controller', 'chartTypes', function ($controller, chartTypes) {
return {
restrict: 'E',
scope: {
'showGrouped': '='
},
controller: function ($scope, $element, $attrs) {
if (chartTypes.indexOf($attrs.type) === -1) {
throw new Error('Chart type ' + $attrs.type + ' is not supported at the moment');
} else {
return $controller($attrs.type + 'Controller', {
$scope: $scope,
$attrs: $attrs
});
}
},
link: function (scope, element, attrs, controller) {
// Rock'n'roll...
controller.init();
}
}
}]);
注意:我现在从指令中删除了ngModel要求,使其更加清晰 如何建立这样的东西。我不确定如何让ngModel与此解决方案一起玩, 但是我确定你能想出那个......如果没有,我很乐意以后试一试。
<强>控制器(一个或多个)强>
app.controller('typeOneController', ['$scope', '$attrs', function ($scope, $attrs) {
var ctrl = this;
ctrl.init = function () {
console.log('We are initialised and ready to rock!');
};
$scope.someFunc = function () {
console.log($scope, 'is the isolate scope defined in the directive');
};
}]);
加价:
<chart type="typeOne" legend="true"></chart>
<chart type="typeTwo" legend="true"></chart>
<chart type="typeThree" legend="true"></chart>
预期结果:
typeOne
此时应该正常滚动,注销我们实际上是初始化的。 typeTwo
应该抛出错误,指出无法找到该名称的控制器(未定义)。 typeThree
应该抛出一个错误,指出当前不支持传入的chartType。 结束时:
现在,这不是你的传统指令结构 - 但我认为它是一个未被充分利用的结构。 将链接功能作为控制器的好处是,您可以完全分离 指令定义中的$ scope行为。
这反过来允许我们单独测试指令本身的$ scope行为,而不是 需要在我们的单元测试中实例化指令及其DOM结构。另外补充道 好处是你不必为不同的图表类型设置多个指令,我们只需要一个控制器(或者,链接行为(如果你愿意的话)) 基于传递给指令定义的图表类型。
这可以进一步构建,包括服务,什么不可以,然后可以在每个图表的基础上(或在指令定义中,将所有图表注入到控制器中)将所有内容注入到控制器中,你有很多灵活性和易于测试的启动。
带回家的另一个教训是,作为指令控制器的匿名函数 hard 进行测试,与其他地方定义的命名控制器相比,然后注入指令。分离是黄金。
让我知道这是否适合您,或者如果您需要更深入的示例来设置它。
我会看看我是否能够获得一整天上传的那种东西。
修改:
添加了jsFiddle展示行为,虽然有点简化(不是孤立的范围,没有templateUrl): http://jsfiddle.net/ADukg/5416/
编辑2 :更新了jsFiddle链接,这个链接是一个隔离的范围,因此调用元素上的ng-click定义不会触发隔离的函数。
编辑3 :添加了一些$ scope函数的示例。
编辑4 :添加了另一个jsFiddle,展示了隔离范围和templateURL。更符合您的工作。
答案 2 :(得分:0)
您应该实施一个名称为&#39; chart&#39;的指令。内部链接功能,您可以访问指令的所有属性&amp;相应地实现功能。 Accessing attributes from an AngularJS directive
答案 3 :(得分:0)
我的建议是有一个模板对象并存储分离的视图文件并调用view.html取决于我们从attr获取的type
var app = angular.module('myApp',[]);
app.directive('chart', function () {
var templates = {
'type-one': 'typeOne.html',
'type-two': 'typeTwo.html'
}
return {
restrict: 'E',
scope: {
'type':'@'
},
templateUrl: function(tElement, tAttrs) {
return templates[tAttrs.type];
},
link: function (scope, element, attrs, ctrl) {
}
}
});
答案 4 :(得分:0)
此解决方案基于angularjs源码,介绍了如何为<input></input>
实现指令 - ngInput
//function to render text input
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
...
}
//function to render number input
function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
...
}
//function to render url input
function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
...
}
var inputType = {
'text': textInputType,
'number': numberInputType,
'url': urlInputType,
...
}
//input directive
var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
return {
restrict: 'E',
require: '?ngModel',
link: function(scope, element, attr, ctrl) {
if (ctrl) {
//logic to use which one to render
(inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
$browser);
}
}
};
}];
答案 5 :(得分:0)
你可以拥有&#34; chart&#34;作为指令,然后根据类型属性委托其他指令,即&#34; chart1&#34;,&#34; chart2&#34;做类似以下的事情: Add directives from directive in AngularJS
答案 6 :(得分:0)
How can I make these directives look for both element name to be chart and type attribute to be present to be processed?
图表是指令的名称,因此如果您错误地使用 chart2 作为名称而不是图表,则您的指令本身不会被处理,因此无法检查指令名称中的拼写错误
关于检查type属性并假设您希望它是强制性的&amp;你有某些预定义的类型。我遵循的技术是为每个要处理的类型定义一个工厂/服务,所以如果我有typeOne&amp; typeTwo图表,我将创建两个单独的工厂。
app.factory("typeOneChart", function(){
var renderOne = function(params) {
// logic for rendering typeOneChart
};
return {
render : renderOne
}
})
app.factory("typeTwoChart", function(){
var renderTwo = function(params) {
// logic for rendering typeTwoChart
};
return {
render : renderTwo
}
})
还注意到返回的函数名在所有工厂中都是相同的,所以它实现了一个接口。
然后在指令中,只需编写一个开关盒,将卸载部件送到特定的工厂。
app.directive('chart', function (typeOneChart, typeTwoChart) {
var linkFunction = function(scope, iElement, iAttrs, ngModelCtrl){
switch(iAttrs.type) {
case 'one':
scope.chartFactory = typeOneChart;
break;
case 'two':
scope.chartFactory = typeTwoChart;
break;
default:
//toastr.error("invalid chart type : " + iAttrs.type);
throw exception("invalid chart type : " + iAttrs.type);
}
scope.chartFactory.render();
}
return {
restrict: 'E',
require: 'ngModel',
scope: { 'ngModel': '=', 'showGrouped': '=' },
link: linkFunction
}
});
这种方法可以使您的指令代码保持最小,加上如果某人指定了无效的图表类型,它只会抛出异常,或者在屏幕上显示和显示错误,您可以立即查看并修复。
现在,特定类型的所有代码都位于其工厂中......因此控制器无法识别每种图表类型的逻辑。