user133688
user133688

Reputation: 7064

Is there a better way to change out a templateUrl in directives

So I have two directives, the functionality is identical the only differences is the template that is being shown. Is there a way to dynamically change the template?

This is what I came up with. Is there a cleaner way?

.directive('tileResource', function ($state) {
  return changeTemplate($state, 'ng-library/templates/tile_view.tpl.html'); 
})

.directive('listResource', function ($state) {   
  return changeTemplate($state, 'ng-library/templates/list_view.tpl.html'); 
})


function changeTemplate($state, template) {
  return {
    scope: {
      'resource': '='
    },
    templateUrl: template,
    link: function (scope) {.... // cool code   }
  }
}

Upvotes: 2

Views: 80

Answers (3)

Samuel Neff
Samuel Neff

Reputation: 74899

Here's a refactoring of your existing code that does the same thing, but I think is clearer in its intentions.

createListDirective('listResource', 'ng-library/templates/list_view.tpl.html'); 
createListDirective('tileResource', 'ng-library/templates/tile_view.tpl.html'); 


function createListDirective(name, template) {
    angular.module('moduleName').directive(name, function ($state) {   
      return {
        scope: {
          'resource': '='
        },
        templateUrl: template,
        link: function (scope) {.... // cool code   }
      }
    }
}

Upvotes: 1

Estus Flask
Estus Flask

Reputation: 222319

Overall idea is fine, but current implementation doesn't look very clean because of dupe dependency arguments, you will also have problems with accessing the function from other modules.

It would be better like this, so you could make full use of Angular DI.

app.factory('baseDirectiveFactory', function (someDirectiveDependency) {
  return function (templateUrl) {
    return {
      templateUrl: templateUrl,
      controller: function () {
        // ...
      }      
    };
  }
})

app.directive('someDirective', function (baseDirectiveFactory) {;
  return baseDirectiveFactory('someTemplate');
});

Though I prefer to keep it closer to OOP approach with mixins:

app.factory('baseDirectiveService', function (someDirectiveDependency) {
  return {
    controller: function () {
      // ...
    }
  };
});


app.directive('someDirective', function (baseDirectiveService) {
  return angular.extend({}, baseDirectiveService, {
    templateUrl: '...'
  });
})

You can also extend the existing directive directly. Angular treats a directive as a service under the hood which contains an array of DDOs, you need the first (and only) DDO if there are no directive name collisions:

app.directive('baseDirective', function (someDirectiveDependency) {
  return {
    controller: function () {
      // ...
    }
  };
})

app.directive('someDirective', function (baseDirectiveDirective) {
  return angular.extend({}, baseDirectiveDirective[0], {
    templateUrl: '...',
    // the inheritance of 'name' property may cause problems later
    name: undefined
  });
})

Upvotes: 1

Mikalai
Mikalai

Reputation: 1525

You can create function like this:

function changeTemplate($state, template) {
  return {
    scope: {
      'resource': '=',
      'template': '='
    },
    template: '<div ng-include="{{template}}"></div>',
    link: function (scope) {.... // cool code   }
  }
}

And just change template argument on parent scope.

Upvotes: -1

Related Questions