Using an AngularJS directive to dynamically incorporate Bootstrap classes in the HTML elements

Our application is now incorporating reusable code by creating a simple directive to display content efficiently.

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:

The HTML code above shows col-md-2 and col-md-9 inside col-md-12. If there are three div elements with content occupying 4, 4, 4 respectively, but the last one has no content, we want the remaining two divs to take up 6 each instead of 4. This behavior needs to be implemented through the directive.

Please let me know if I need to clarify anything further.

Answer №1

To implement dynamic column sizing in Bootstrap, you can create a custom directive that watches for changes in the DOM structure and then adds corresponding Bootstrap classes.

Custom 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);
                    }
                });
            });
        }
    }
});

Usage in HTML

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

Check out the demo on JSFiddle

Answer №2

Providing a generic example for usage, allowing you to customize it with your own content. Let's say you have three variables accessible in your scope: content, content2, and content3. Here is an example of how you can use them:

<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>

By default, the columns will have a width of col-md-6, but if there is content in the 3rd column, then the class col-md-4 will also be applied to ensure equal division among all three columns. The col-md-4 class takes priority over col-md-6.

Alternatively, for more clarity, you can utilize this structure as well:

<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>

Answer №3

After utilizing ng-class, you have the option to implement a function that will determine 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing async/await in JavaScript within a class structure

I am facing a dilemma in using the new async/await keywords within the connect method of my JavaScript class. module.exports = class { constructor(url) { if(_.isEmpty(url)) { throw `'url' must be set`; } ...

Tips for receiving notifications when the Collapsible collapses

I'm having trouble figuring out how to receive notifications when the Collapsible is expanded and collapsed. Currently, I am not receiving any type of notification. Any suggestions on how to make this work? Below is my code: --Imported jQuery < ...

Compatibility with IE9: Using jQuery to send an AJAX POST request

I'm currently facing an issue with making a POST request from my website to a server that is not on the same domain. The functionality is working seamlessly on Chrome, Firefox, and IE10+, but I need to ensure it works on IE9 as well. Below is the cod ...

What is the process for creating a server-side API call?

I've designed a front-end application that uses an API to retrieve data. The problem I'm facing is that in order to access the API, I need to use an API Key. If I include the API key in the client-side code, it will be visible to users. How can I ...

limitation in bootstrap ensures that only one collapse element is open at any

Hey, can someone help me fix this code? I'm trying to make it so that only one element opens at a time, but I can't seem to figure out how. Right now, if I click on two elements, they both open and the other one doesn't close. This is what ...

Tips on resolving the distinct key issue in React and eliminating it

Attention all React beginners! I'm encountering an issue that states: Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `resultTable`. See https://fb.me/react-warning-keys for more information. ...

Exploring the proper syntax of the reduce() method in JavaScript

Here are two codes that can be executed from any browser. Code1: let prices = [1, 2, 3, 4, 5]; let result = prices.reduce( (x,y)=>{x+y} ); // Reduces data from x to y. console.log(result); Code2: let prices = [1, 2, 3, 4, 5]; let result = prices.red ...

Dynamically load scripts in angularJs

Having multiple libraries and dependencies in my angularjs application is posing a challenge as I want to load them all using just one script, given that three apps are utilizing these dependencies. Currently, I have this custom script: var initDependenci ...

What is the best way to utilize JQuery AJAX to send XML data for a delete request?

I am having trouble sending XML type data to the backend using jQuery and AJAX as a DELETE request. When I do this, I receive an empty array from the backend's request body. How can I properly send the ID? Below is the code I am using: function delet ...

Guide on updating and storing changes in a JSON file named 'file.json' using jQuery or JavaScript

I'm working with a JSON file and attempting to make updates using jQuery. However, I'm encountering an issue where I can't seem to save the update once the script has finished running. Is there a way to save the update without relying on se ...

Establish a route nickname for files outside the project directory

I'm currently tackling a project that is divided into multiple angular projects. Within these projects, there are some services that are shared. Is there a way for me to incorporate these services into my project without encountering errors? /root / ...

Creating a triangle shape using Bootstrap to style a div element, similar to the image provided

Trying to achieve the look of the attached image with a few divs. I know I can use a background image like this: background:url(image.png) no-repeat left top; But I'm curious if there's another way to achieve this without using a background ima ...

Tips for updating the appearance of a ListItem with a click action

For my current project, I am using Material UI and React. One of my components is structured as follows: import React, { Component } from 'react'; import { List, ListItem } from 'material-ui'; import PropTypes from 'prop-types&apo ...

Having trouble modifying a nested object array within a treeview component in Reactjs

Thanks for your help in advance! Question: I'm having trouble updating a nested object of an array in a treeview using Reactjs. Please refer to the code and sandbox link below: https://codesandbox.io/s/cocky-leakey-ptjt50?file=/src/Family.js Data O ...

The alignment for Bootstrap's NAV element within a display:table-cell element seems to be off when viewed on Firefox浪

Here is an example of HTML markup with Bootstrap library included: <div class="container"> <div class="card"> <ul class="nav list"> <li class="element"> <a href="#">Element</a> </li> ...

Customize the behavior of jQuery cycle with an <a> tag

Can the jQuery cycle be accessed through a link in order to override the i variable? I've come across examples that can achieve this, but not in a scenario like this where the cycle() function is located within a variable: $(document).ready(function ...

The lookAt method in THREE.js is not functioning properly when called after the rendering process

The code snippet below seems to be causing some issues. It requires jquery and three.js to function properly. The problematic lines are as follows: // change the view so looking at the top of the airplane views[1].camera.position.set( 0,5,0 ); views[1].ca ...

Navigate the page by scrolling the absolute positioned div

Is it possible to make the fancybox modal scroll with the page using fancybox 2? I want it to move along with the content rather than being fixed in the center with a max-height restriction. How can I achieve this? $('.fancybox-open').fancybox({ ...

Anticipated outcome for absent callbacks in module API implementation

I am seeking advice on the expected behavior when developing a Node module API. It is becoming complicated in my module implementation to check if the caller has provided a callback before calling it. I am starting to believe that it may be the user's ...

Utilizing useEffect in the header component of ReactJS/Next.js: A Comprehensive Guide

In my next.js/react project, I have a component called header.js that is included on every page. Within this component, I've implemented a typewriter effect with rotation by using the following code snippet inside useEffect: export default function H ...