1

I want to truncate my table cells but fit as much as possible content into them. There is an excellent solution (fiddle) which I want to implement in a directive. I need to transform a table cell from

<td>veryverylongunbreakablecontent</td>

to

<td>
  <div class="container">
    <div class="content">veryverylongunbreakablecontent</div>
    <div class="spacer">veryv&shy;erylon&shy;gunbr&shy;eakab&shy;lecon&shy;tent</div>
    <span>&nbsp;</span>
  </div>
</td>

This is a simplified example. My table cells consist of angular scope variables:

<td>{{ item.attribute.verylong }}</td>

What I have come up with so far is a directive

.directive('mwTableTruncate', function ($compile) {
  return {
    restrict: 'A',
    templateUrl: 'modules/ui/templates/mwComponents/mwTableTruncate.html',
    transclude: true,
    compile: function( tElem, tAttrs ){
    }
  };
});

with a template

<div class="containerTest">
  <div class="content">
    <div ng-transclude></div>
  </div>
  <div class="spacer">
    <div ng-transclude></div>
  </div>
  <span>&nbsp;</span>
</div>

Now I need to add soft hyphens (&shy;) every 5 characters to the text in the spacer div. How can I do this?

The problem is I need to access the spacer div text after all the scope variables have been translated to add the soft hyphens.

edit#1 @sirrocco

I have examined the output from the compile, pre-link, link, post-link phase. None of these phases do translate the scope variables.

link phase

.directive('mwTableTruncate', function ($compile) {
  return {
    restrict: 'A',
    link: function (scope, iElem, attrs) {
      console.log('link => ' + iElem.html());
      console.log('link text => ' + iElem.text());
    }

  };
});

gives me in the console:

link => 
      {{ item.attributes.surname }}

link text => 
      {{ item.attributes.surname }}

compile, pre-link, post-link

.directive('mwTableTruncate', function ($compile) {
  return {
    restrict: 'A',
    templateUrl: 'modules/ui/templates/mwComponents/mwTableTruncate.html',
    transclude: true,
    compile: function( tElem, tAttrs ){
      console.log('Compile => ' + tElem.html());
      return {
        pre: function(scope, iElem, iAttrs){
          console.log('pre link => ' + iElem.html());
          console.log('pre link text => ' + iElem.text());
        },
        post: function(scope, iElem, iAttrs){
          console.log('post link => ' + iElem.html());
          console.log('post link text => ' + iElem.text());
          //debugger;
        }
      };
    }
  };
});

output in the console:

pre link =>     <div class="containerTest">
      <div class="content">
        <div ng-transclude=""></div>
      </div>
      <div class="spacer">
        <div ng-transclude=""></div>
      </div>
      <span>&nbsp;</span>
    </div>
pre link text =>     






       

post link =>     <div class="containerTest">
      <div class="content">
        <div ng-transclude=""><span class="ng-binding ng-scope">
          {{ item.attributes.surname }}
        </span></div>
      </div>
      <div class="spacer">
        <div ng-transclude=""><span class="ng-binding ng-scope">
          {{ item.attributes.surname }}
        </span></div>
      </div>
      <span>&nbsp;</span>
    </div>
post link text =>     


          {{ item.attributes.surname }}




          {{ item.attributes.surname }}

As you can see, none of the {{ item.attributes.surname }} variables got translated.

edit#2

Based on the hint with the timeout function in the post link phase I have come up with this solution:

directive

.directive('mwTableTruncate', function($timeout) {
  return {
    restrict: 'A',
    templateUrl: 'modules/ui/templates/mwComponents/mwTableTruncate.html',
    transclude: true,
    compile: function() {

      var softHyphenate = function (input) {
        var newInput = '';
        for (var i = 0, len = input.length; i < len; i++) {
          newInput += input[i];
          if (i % 5 === 0) {
            newInput += '&shy;';
          }
        }
        return newInput;
      };

      return {
        post: function (scope, iElem) {
          $timeout(function () {

            var text = iElem.find('div.spacer').text().trim();

            // add tooltips
            iElem.find('div.content').prop('title', text);

            // add soft hyphens
            var textHyphenated = softHyphenate(text);
            iElem.find('div.spacer').html(textHyphenated);

          });
        }
      };
    }
  };
});

template

<div class="containerTest">
  <div ng-transclude class="content"></div>
  <div ng-transclude class="spacer"></div>
  <span>&nbsp;</span>
</div>

How would it look like with an isolated scope sirrocco rbaghbanli?

Community
  • 1
  • 1
mles
  • 4,534
  • 10
  • 54
  • 94
  • using the link function instead of compile should put you in the post-link phase when the variables have been interpreted. Have you tried using link instead of compile ? – sirrocco May 26 '15 at 18:15
  • yepp, updated the question – mles May 26 '15 at 18:49
  • 1
    move the postlink code inside a $timeout function, that should ensure that the digest cycle has ran – sirrocco May 26 '15 at 18:53
  • I think you could also use isolated scope, pass in the longText variable, and then you have access to without the need for wait for timeout. You can then also drop the transclude attribute. rbaghbanli was right from the start . – sirrocco May 27 '15 at 03:41
  • How would you do it with an isolated scope? – mles May 27 '15 at 06:05

2 Answers2

2

Do not transclude. Simply set your item.attribute.verylong as ng-model for your directive. Then get the object to manipulate as you wish. In the controller add all spacers you need. Then just display the result in {{ ... }} in your template for directive. Code:

.directive('truncateString', function ($compile) {
  return {
    restrict: 'E',
    templateUrl: '{{ strWithBreaks }}',
    scope: {
      str: '=ngModel'
    },
    controller: ['$scope', function ($scope) {
     $scope.strWithBreaks = (function (input) {
         var newInput = '';
         for (var i = 0, len = input.length; i < len; i++) {
           newInput += input[i];
           if (i % 5 === 0) {
             newInput += '&shy;';
           }
         }
         return newInput;
       })(str);
    }]
  };
});

Usage:

<truncate-string ng-model="myVeryLongString"></truncate-string>
Riad Baghbanli
  • 3,105
  • 1
  • 12
  • 20
  • Could you extend your code example? I've updated the question with an example how to do it with transclude. – mles May 27 '15 at 06:03
1

The directive without transclude would probably look something like:

.directive('mwTdTruncate', function() {
  return {
    restrict: 'A',
    templateUrl: 'modules/ui/templates/mwComponents/mwTableTruncate.html',
    scope:{
        longText: '@mwLongText'
    },
    replace:true,
    link: function(scope) {

      var softHyphenate = function (input) {
        var newInput = '';
        for (var i = 0, len = input.length; i < len; i++) {
          newInput += input[i];
          if (i % 5 === 0) {
            newInput += '&shy;';
          }
        }
        return newInput;
      };

      scope.softText = softHyphenate(scope.longText);
    }
  };
});

and the template:

<td>
  <div class="container">
    <div class="content">{{longText}}</div>
    <div class="spacer">{{softText}}</div>
    <span>&nbsp;</span>
  </div>
</td>

used like:

<td mw-td-truncate mw-long-text='{{yourTextVariable}}'>veryverylongunbreakablecontent</td>
sirrocco
  • 7,975
  • 4
  • 59
  • 81