Angular JS Directive - шаблон, компиляция или ссылка?

Я хотел бы создать директиву Angular JS для проверки длины строки, если она слишком длинная, чтобы сократить ее с помощью фильтра и показать Angular -UI popover on mouseover.

Где в директиве я должен помещать функциональные возможности, чтобы заставить это работать (ссылка, шаблон или компиляция)?

Вид:

<div myapp-shorten="project">{{project.Description}}</div>

Вот мои первые попытки в этой директиве:

angular.module('myapp.directives', [])
 .directive('myappShorten', function () {

    function link(scope, element, attrs) {

        var outputText = "";

        if (myappShorten.Description.length > 20) {
            outputText += "<div popover='{{myappShorten.Description}}' popover-trigger='mouseenter'>" +
            "{{myappShorten.Description | cut:true:20:' ...'}}</div>";
        } else {
            outputText += "<div>{{myappShorten.Description}}</div>";
        }

        element.text(outputText);
    }

    return {
        link: link,
        scope: {
            myappShorten: "="
        }
    };

});

Ответ 1

Прежде всего, вы можете изменить фильтр, чтобы он не изменял строку, если ей не нужно

Во-вторых, поскольку вам нужен только фильтр и шаблон popover - достаточно.

 angular.module('myapp.directives', [])
   .directive('myappShorten', function () {

     return { 
       scope: { data : '=myappShorten',
       template:"<div popover='{{data.Description}}' popover-trigger='mouseenter'>" +
        "{{ data.Description | cut:true:20:' ...' }}</div>"
     }
   })

В качестве альтернативы вы можете использовать комбинацию ng-show и ng-hide

 app.directive('shorten', function () {
return {
    restrict: 'A'
    , scope :  {
        shorten : '=',
        thestring: '='   
    }
    , template: "<div ng-show='sCtrl.isLong()' tooltip='{{ sCtrl.str }}'>{{ sCtrl.short() }}</div>"+
                "<div ng-hide='sCtrl.isLong()'>{{ sCtrl.str }}</div>"

    , controllerAs: 'sCtrl'
    , controller: function ($scope) {
        this.str = $scope.shorten || ''
        this.length = $scope.thestring || 20

        this.isLong = function() {
            return this.str.length > this.length   
        }

        this.short = function() {
            if ( this.str.length > this.length)  {
                return this.str.substring(0,this.length)  + '...'                    
            }
        }                                  
    }                               
  }       
})

Третий вариант - фактически использовать компиляцию и $watch на myappShrten.Description, но, похоже, это слишком много для меня.

Ответ 2

Вышеприведенный ответ работает отлично. Но если значение thestring изменяется, это не будет обновляться по мере компиляции контроллера при первом запуске, а затем не будет обновляться, если значение изменится. Ввод кода в controller компилируется заранее, но ввод кода в функцию link позволяет ему обновляться, если значение изменяется. Это мое предпочтительное решение, основанное на решении выше:

Вид:

<shorten thestring="project.Description" thelength="40"></shorten>

Директива:

.directive('shorten', function () {
    return {
        restrict: 'E'
        , scope: {
            thelength: '=',
            thestring: '='
        }
        , link: function postLink(scope, iElement, iAttrs) {
            scope.isLong = function () {
                return scope.thestring.length > scope.thelength
            }

            scope.short = function () {
                if (scope.thestring.length > scope.thelength) {
                    return scope.thestring.substring(0, scope.thelength) + '...'
                }
            }

        }

        , template: "<div class='handCursor' ng-show='isLong()' tooltip='{{ thestring }}'>{{ short() }}</div>" +
                    "<div ng-hide='isLong()'>{{ thestring }}</div>"
    }
});