3

I'm attempting to create a custom angular component that dynamically loads a template based on a templateUrl function. I currently get a templateUrl is not using explicit annotation and cannot be invoked in strict mode' error. Normally I understand that this error crops up when an injected service doesn't get properly annotated (https://docs.angularjs.org/error/$injector/strictdi). However, I am missing how this applies to templateUrl.

I'm using Angular 1.5.

Exact error message is - angular.js:13550 Error: [$injector:strictdi] templateUrl is not using explicit annotation and cannot be invoked in strict mode

Component Code snippet:

angular.module('hive.triGrid')
.controller('TriGridCellController', ['$element', '$attrs', function     ($element, $attrs) {
    var $ctrl = this;
}]) 
.component('triGridCell', {
controller: 'TriGridCellController',
templateUrl: function($element, $attrs)
{
    var type = $attrs.cellType;
    if(type.toUpperCase() == "ICON")
    {
        return "components/grid/cellTemplates/iconCell.tpl.html";
    }
    else if(type.toUpperCase() == "CUSTOM")
    {
        return $attrs.cellTemplateUrl;
    }
    else
    {
        return "components/grid/cellTemplates/textCell.tpl.html"; 
    }
},
//template:"<ng-include src='$ctrl.getTemplateUrl(z)'/>",
bindings: {
    cellData:'<',
    cellType: '<', //See triGridRow and triGrid for config JSON format.
    }
});

EDIT: Code after answer was applied:

templateUrl: ['$element', '$attrs', function($element, $attrs)
{
    var type = $attrs.cellType;
    if(type.toUpperCase() == "ICON")
    {
        return "components/grid/cellTemplates/iconCell.tpl.html";
    }
    else if(type.toUpperCase() == "CUSTOM")
    {
        return $attrs.cellTemplateUrl;
    }
    else
    {
        return "components/grid/cellTemplates/textCell.tpl.html"; 
    }
}],
Joseph
  • 1,442
  • 21
  • 44

1 Answers1

5

As said in this answer, $element and $attrs are injected into templateUrl function, not just passed as arguments. This is the difference between element parameter name (in link or compile functions) and $element local dependency in DI-enabled functions that Angular documentation emphasizes.

templateUrl function is invoked by injector in components, so any other services can be injected there as well, and it should be properly annotated.

Community
  • 1
  • 1
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • For some reason I didn't think to apply that to the component setup functions. That worked for me. – Joseph Jul 15 '16 at 13:17
  • This is a substitute for directive factory function, so services could be injected in every place in component where they are needed. – Estus Flask Jul 15 '16 at 13:21
  • One issue I'm still facing is that the $attrs.cellType returns the raw text from my template, not the actual controller value that should be getting passed in. I'm attempting to resolve a template based on configuration, rather than predetermined text. In this case do I need to start dabbling into compiling and linking as well as using a raw directive? – Joseph Jul 15 '16 at 17:29
  • 1
    That's correct. As noted in the linked answer, `templateUrl` cannot be used to obtain interpolated attributes, because the function is executed before directive `compile` and long before the first digest. Components are supposed to be straightforward self-contained widgets, and what you're trying to do is similar to ng-include directive, which is hacky and complex enough. If it is possible to make $attrs.cellType static and use its raw value, this will save you a lot of troubles. – Estus Flask Jul 15 '16 at 17:42
  • Not possible to use static values, but I can turn it into a directive instead of a component. – Joseph Jul 15 '16 at 17:54