1

We are implementing reusable code in our application for this purpose we have created a simple directive which displays content.

Directive Code:

angular.module("newsStore.moduleDirectives", [])
    .directive('renderAboutContent', ['aboutService', renderAboutContent]);

function renderAboutContent(aboutService) {
    return {
        restrict: 'AE',
        scope: {},
        templateUrl: 'templates/about.html',
        link: function (scope, element) {
            aboutService.getAboutContent()
                .then(function (results) {
                    scope.aboutList = results.aboutContent.listItems;
                }, function (error) {
                    console.log('controller error', error);
                });
        }
    }
}

HTML code:

<div class="col-md-12 aboutUs-ph padT10 content-ph_abt" ng-repeat="content in aboutList">
    <div class="col-md-2 form-group" ng-if="content.image">
        <img src="{{content.image}}" class="img-responsive" />
    </div>
    <div class="col-md-9">
        <span class="guidedTourText"><b>{{content.title}}</b></span>
        <br>
        <span>{{content.description}}</span>
    </div>
</div>

Question:

In the above HTML you can see col-md-2 and col-md-9 inside col-md-12, let's say I have three div elements, and three of them occupies 4, 4 ,4 if the content is present. Let's say if the content is not present in the last div then the remaining two div's should take 6,6 and vice versa. We want this to be implemented from the directive.

Let me know if I am not clear.

Angular Learner
  • 390
  • 4
  • 16
  • I would set up a $watch inside of your link function. The $watch would monitor a function, and that function would look for DOM changes (i.e. DIV children changes). Depending on the state of the DOM, then dynamically add the col-* attributes. – Michael Kang Nov 06 '15 at 05:16
  • Thanks for the comment @pixelbits, but I am new to angular js , can you show me how to implement the above $watch in my directive. – Angular Learner Nov 06 '15 at 05:21
  • did u tried ng-class? check this http://stackoverflow.com/questions/7792652/what-is-the-best-way-to-conditionally-apply-a-class & https://scotch.io/tutorials/the-many-ways-to-use-ngclass. – Vijayakumar Selvaraj Nov 06 '15 at 06:03

3 Answers3

1

I would set up a $watch inside of your link function. The $watch would monitor a function, and that function would look for DOM changes (i.e. DIV children changes). Depending on the state of the DOM, then dynamically add the col-* attributes

Directive

app.directive('bootstrapColumns', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attr) {
            if (!element.hasClass('row'))
                element.addClass('row');


            scope.$watch(function() {
                var elems = element[0].childNodes;
                var count =0;
                angular.forEach(elems, function(e) {

                    if (e.tagName == 'DIV' && angular.element(e).text() != '')
                        ++count;
                });
                return count;
            },
            function(cols) {
                var colNum = 12 / cols;
                var cssClass = 'col-xs-' + colNum;
                var elems = element[0].childNodes;
                angular.forEach(elems, function(e) {
                    if (e.tagName == 'DIV') {
                        var div = angular.element(e);                  
                        if (div.text() != '' && !div.hasClass(cssClass))
                            div.addClass(cssClass);
                    }
                });
            });
        }
    }
});

HTML

<div bootstrap-columns>
   <div>Column1</div>
   <div>Column2</div>  
</div>

Demo Fiddle

Michael Kang
  • 52,003
  • 16
  • 103
  • 135
  • thanks for the answer, I just have one quick question, I am trying to use your solution in my application.I have followed your example.
    Column1
    column1-child
    Column2
    In the above example the col-md width applies for the inner child div too, we don't want the child div's affecting only the parent div should have the width. Can you tell me how to avoid the child div's from this?
    – Angular Learner Nov 09 '15 at 05:59
  • 1
    Updated to only look at immediate child DIVs – Michael Kang Nov 10 '15 at 00:33
  • Thanks for the answer bro @pixelbits, one last question I know this lot, as my Project lead keeps on changing the requirement :). Here is the question
    Column1
    Column2
    Column3
    In this case he wants the first and last div to take the width as col-md-3 and the middle as col-md-6, so if the any one of the first and last are not present the middle one takes col-md-9 and the other takes col-md-3.
    – Angular Learner Nov 10 '15 at 07:20
1

I'm giving you a generic usage, you can easily write it with your content. Suppose you have three variables available in your scope: content, content2 and content3. Now you can write like this:

<div class="row">
    <div class="col-md-6" ng-class="{'col-md-4': content3}">{{content1}}</div>
    <div class="col-md-6" ng-class="{'col-md-4': content3}">{{content2}}</div>
    <div class="col-md-4" ng-show="content3">{{content3}}</div>
</div>

So what is happening here is, by default the col-md-6 will be given to the columns and if there is there is content in the 3rd column then we will also the class col-md-4 so that all three columns can be equally divided. col-md-4 will take precedence over col-md-6.

Or, if you want more clearance, you can simply write this also:

<div class="row">
    <div ng-class="{'col-md-4': content3, 'col-md-6': !content3}">{{content1}}</div>
    <div ng-class="{'col-md-4': content3, 'col-md-6': !content3}">{{content2}}</div>
    <div class="col-md-4" ng-show="content3">{{content3}}</div>
</div>
Shashank Agrawal
  • 25,161
  • 11
  • 89
  • 121
1

As a follow up to using ng-class, you can also use a function that returns the class:

var app = angular.module('app', []);

app.directive('aboutDirective', function renderAboutContent(aboutService) {
  return {
    restrict: 'AE',
    scope: {},
    templateUrl: 'about.html',
    link: function(scope, element) {
      aboutService.getAboutContent()
        .then(function(results) {
          scope.aboutList = results.aboutContent.listItems;
        }, function(error) {
          console.log('controller error', error);
        });
      scope.colWidth = function(content) {
        return content.image && content.something ? 'col-xs-4' : 'col-xs-6';
      }
    }
  }
});

app.factory('aboutService', function($timeout) {
  return {
    getAboutContent: function() {
      return $timeout(function() {
        return {
          aboutContent: {
            listItems: [{
              image: 'image1',
              title: 'title1',
              description: 'desc1',
              something: 'something1'
            }, {
              image: 'image2',
              title: 'title2',
              description: 'desc2'
            }, {
              title: 'title3',
              description: 'desc3',
              something: 'something3'
            }]
          }
        };
      }, 1000);
    }
  };
});
.row {
  display: flex;
  text-align: center;
  color: #fff;
}
.image {
  background-color: #75b5aa;
  border: 1px solid #000;
}
.middle {
  background-color: #aa759f;
  border: 1px solid #000;
}
.something {
  background-color: #6a9fb5;
  border: 1px solid #000;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.css">

<div class="container" ng-app='app'>
  <about-directive></about-directive>
  
  <script type="text/ng-template" id="about.html">
    <div class="row" ng-repeat="content in aboutList">
      <div ng-if="content.image" class="image" ng-class="colWidth(content)">
        {{ content.image }}
      </div>
      <div class="middle" ng-class="colWidth(content)">
        <span><b>{{content.title}}</b></span>
        <br>
        <span>{{content.description}}</span>
      </div>
      <div ng-if="content.something" class="something" ng-class="colWidth(content)">
        {{content.something}}
      </div>
    </div>
  </script>
</div>
dting
  • 38,604
  • 10
  • 95
  • 114