问题
I am trying to create some sort of generic gridview using AngularJS 1.5 and its components. A (pseudocode) version of what I've got going right now:
// inside <my-grid-component data="data" metadata="metadata">
<div ng-repeat="item in $ctrl.data">
<my-row-component item="item" metadata="$ctrl.metadata"></my-row-component>
</div
// inside <my-row-component item="item" metadata="metadata">
<div ng-repeat="column in $ctrl.metadata.columns">
<my-cell-component value="$ctrl.item[column]"></my-cell-component>
</div>
Now <my-cell-component>
could have some basic ng-switch
statement that handles the obvious cases, like if the value is text or an image or something, but since this will be used by many people and on many projects, it is possible that someone will want to do something fancy and/or highly specific inside a cell. They could just ammend <my-cell-component>
with more ng-switch
es, but then they are messing with base framework code which hurts maintainability.
So, ideally, I'd want to make something where a developer can optionally provide his own custom template for a specific field in the metadata, e.g. metadata.columns[3].customCellComponentName = 'some-custom-template';
Then <my-row-component>
would look something like this:
<div ng-repeat="column in $ctrl.metadata.columns">
<div ng-if="!column.isCustomCellComponent">
<my-cell-component value="$ctrl.item[column]"></my-cell-component>
</div>
<div ng-if="column.isCustomCellComponent">
??? --> <column.customCellComponentName value="$ctrl.item[column]"></column.customCellComponentName>
</div>
</div>
The project automatically puts all templates in $templateCache, so resolving the template should not be a problem, but other than that, the marked line with the "???" obviously does not work. It demonstrates what I would like to achieve, but I have no idea how to actually do something like this. I looked into transclusion, ng-include
and other solutions, but none seem to provide the option to dynamically load a template AND model-bind some data to it.
Any and all ideas very much welcome. I would like to stay as far away from overly complex directives as possible. While they allow you to do many things, in my experience they are also a debugging and maintainability nightmare.
Thanks.
回答1:
You can create a directive for your <my-cell-component>
such a way that it either accepts a templateUrl
or it determines the templateUrl
and uses it. Let me give you an example for the latter,
angular.module('myApp')
.directive('myCellComponent', ['CELL_TYPE', function (CELL_TYPE) {
return {
restrict: 'E',
scope:{
cellType: '='
},
template: '<div ng-include="templateUrl"></div>',
link: function (scope) {
function setTemplate(cellType) {
scope.templateUrl = CELL_TYPE[cellType.value].templateUrl;
// or figure out some other way to determine templateUrl
}
scope.$watch(function () {
return scope.cellType;
}, function (newVal) {
if(newVal) {
setTemplate(scope.cellType);
}
});
}
};
}]);
So, we've got the directive's template having an ng-include
that uses the templateUrl
determined on the basis of some constants, say CELL_TYPE
.
Now you've got a directive that dynamically loads its template based on your attributes!
You can (obviously) get rid of $watch
if dynamically changing the templateUrl
isn't applicable to your use-case.
来源:https://stackoverflow.com/questions/36544681/angular-1-5-dynamically-load-a-component