2

This is probably going to be a bit complicated, so I will try to keep it as easy as I can. I have a directive:

.directive('configuratorRows', function () {
    return {
        restrict: 'A',
        scope: {
            garments: '=configuratorRows',
            templateUrl: '&',
            colours: '='
        },
        templateUrl: 'assets/tpl/directives/configuratorRows.tpl.html',
        controller: 'ConfiguratorRowsDirectiveController',
        link: function (scope, element, attrs, controller) {

            // Assign our garments to our controller
            controller.garments = scope.garments;
            scope.rows = controller.rows;

            // Invoke our calculation function
            controller.buildRows();
        }
    };
});

This directive is in charge of working out how many rows of "garments" should be shown in a particular area. On one of my views I invoke it two times like this:

<div configurator-rows="controller.sportswear" colours="controller.colours" ng-if="controller.sportswear.length">
</div>

<div configurator-rows="controller.leisurewear" colours="controller.colours" ng-if="controller.leisurewear.length"> 
</div>

So far so good, on this page I get a list of different garments based on their type (leisurewear of sportswear) and everything works as it should. The template for this directive looks like this:

<div class="row flex-xs" ng-repeat="row in rows">
    <div class="col-md-4 col-sm-6 text-center flex-xs flex-end" ng-repeat="garment in row track by $index">
        <div class="kit-template" configurator="garment" colours="colours" designs ng-if="garment"></div>
    </div>
</div>

As you can see, there is another directive in here, this just displays an SVG image for each garment in a row. Now, I have another area (on the same view) which lists all garments and displays them slightly differently. The same rules apply, so I would like to use my configuratorRows directive, but the problem is the "template" is different, I want it to look like this:

<div class="row">
    <div class="col-xs-4 total-item" ng-repeat="garment in kit.garments">
        <div class="row">
            <div class="col-xs-4 kit-template" configurator="garment" colours="colours" designs></div>

            <div class="col-xs-8">
                <h4 class="total-title">{{ garment.title }}</h4>
                <p>Quantity: <button class="btn btn-xs btn-primary" type="button" ng-disabled="garment.quantity <= 10" ng-click="modifyQuantity(garment)"><span class="fa fa-minus"></span></button> <span class="text-black">{{ garment.quantity }}</span> <button class="btn btn-xs btn-primary" type="button" ng-click="modifyQuantity(garment, true)"><span class="fa fa-plus"></span></button></p>
            </div>
        </div>
    </div>
</div>

I started down the route of allowing a templateUrl override, but then I realised that the area where I am placing this directive is also a directive and has functions assigned to each bit (check the Quantity buttons).

So my next option was to make the configuratorRows directive without a template and just use ng-transclude instead. The problem with that, is that having more than one configuratorRows in a view seemed to mess around with the scope for each one. So in one I might have 4 rows, but in another I might have 2.

Does anyone know how I can get around this problem elegantly?

3 Answers 3

1

I'm not sure if I understand your goal properly, but if you want to change the directive template, in the directive you can do :

templateUrl: function(element,attrs){
    return attrs.type==='all' ? 'configuratorRows.all.tpl.html' :  'configuratorRows.single.tpl.html'; 
}

Usage:

<div type="single" configurator-rows="controller.leisurewear" colours="controller.colours" ng-if="controller.leisurewear.length"></div>
<div type="all" configurator-rows="controller.leisurewear" colours="controller.colours" ng-if="controller.leisurewear.length"></div>
Sign up to request clarification or add additional context in comments.

2 Comments

Looks like this was added in Angular 1.3, and if you don't have an IE8 support requirement, this is the better answer. EDIT Nevermind, just not in the 1.2 documentation.
Yeah, I didn't know about this useful feature for long time... :P
0

If you are looking for a "simply different presentation" of the same template structure, you probably need a different css approach (for example, in sass, have a look on the bem approach)

If you need a different template structure, instead, you have to choose the template at-runtime (based, for example, on the templateUrl property of the scope).

angular
  .module('test', [])
  .directive('tpl', function() {
    return {
      scope: {
        type: '@'
      },
      restrict: 'E',
      //templateUrl: function(elem, attr){
      template: function(elem, attr){
        console.log('suca');
        var tpl = '';
        switch((attr.type || '').toLowerCase()) {
            
            case 'heading':
              tpl += '<h1>Heading</h1>';
              break;
            
            default:
              tpl += '<div">Normal Div Element </div>';
        }
        
        return tpl;
      }
    };
  })
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<article data-ng-app="test">
  <tpl data-type="heading"></tpl>
  <tpl></tpl>
</article>

Comments

0

One thing you could do, though it might be a bit more cumbersome to set up than you might like is to create two different template files configuratorBase.html and configuratorAlt.html and attach those to two different directives which share the scope (that is a non-isolate scope).

.directive('configuratorBase', [function() {
    var configuratorBase = {
        restrict: 'AE',
        templateUrl: '/path/to/configuratorBase.html'
    };
    return configuratorBase;
});

Then your configurator directive could look something like:

.directive('configurator', ['$compile', function($compile) {
    var configurator = {
        restrict: 'AE',
        link: configuratorLink(scope, element, attributes, controllers) {
            /** if evaluating you need the base */
            var template = angular.element('<configuratorBase/>');
            $compile(element.append(template))(scope);
        }
    };
    return configurator;
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.