Damian Czapiewski
Damian Czapiewski

Reputation: 881

Dynamic <svg-icon> as Angular directive

I'm using SVG icons contained in a sprite, like below.

<div class="py-3">
    <svg-icon><src href="sprite.svg#si-glyph-bullet-checked-list"/></svg-icon>
    <span>Tasks</span>
</div>

And it works fine, yet when I rewrite it to Angular directive:

app.directive('ngxTileIcon', function () {
    return function (scope, element, attrs) {
        var tileIcon = attrs['ngxTileIcon'];
        var tileCaption = element.text();
        element.text('');
        element.addClass('py-3');
        element.append(
            $('<svg-icon/>').append(
                $('<src/>').attr('href', 'sprite.svg#si-glyph-' + tileIcon)
            ),
            $('<span/>').text(tileCaption)
        );
    };
});

And use it:

 <div ngx-tile-icon="bullet-checked-list">Tasks</div>

Basically, I'm getting the same markup but Google Chrome does not display that an SVG element has been added to the DOM. When using non-Angular approach, it does. Finally, when using Angular directive, the icon is not displayed.


SOLVED

I just changed the approach - instead of adding the markup to the element, I'm directly replacing its content with html(). Now it works as expected.

app.directive('ngxTileIcon', function () {
    return function (scope, element, attrs) {
        var tileIcon = attrs['ngxTileIcon'];
        var tileCaption = element.text();
        var $tempDiv = $('<div/>');
        element.addClass('py-3');
        $tempDiv.append(
            $('<svg-icon/>').append(
                $('<src/>').attr('href', 'sprite.svg#si-glyph-' + tileIcon)
            ),
            $('<span/>').text(tileCaption)
        );
        element.html($tempDiv.html());
    };
});

Upvotes: 0

Views: 1845

Answers (2)

Duncan Thacker
Duncan Thacker

Reputation: 5188

Damian has pointed out that this answer is wrong, but I'll leave it up to prevent anyone else making the same mistake!

<svg-icon> is an Angular directive and not a native HTML element, so adding it in using jQuery will not trigger Angular's logic and you're just left with nothing.

In general with Angular 1.x (assuming you're using 1.x?), you should give it a template field which will create the icon based on the input:

app.directive( "myDirective", function() {
   return {
      template: "<div class='py-3'><svg-icon><src href='sprint.svg#si-glyph-{{ tileIcon }}'></src></svg-icon></div>"
      scope: {
         tileIcon: "<"
      }
   };
});

This should bind the "tileIcon" variable to the supplied attribute in the parent element, and then inject it in the template, with databinding so that it updates when the parent updates. });

Upvotes: 1

Maxim Shoustin
Maxim Shoustin

Reputation: 77904

Its not what you are asking but it can help you to sort things out.

Take a look on this simple example how works svg builder with directive.

<button>
   <my-icon   
          icon="arrow_left"  
          size="18" 
          style="fill:#37393B;"></my-icon>
</button>  

directive:

app.directive('myIcon', function () {
    var shapes = {
        'arrow_left':
                'viewBox="-358 231.3 125 133"  >' +
                '<rect x="-342.8" y="262.7" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 -315.0274 678.5285)"  width="89.5" height="22.6"/>' +
                '<rect x="-342.8" y="309.9" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 -736.0015 337.5721)"  width="89.5" height="22.6"/>' +
              '</svg>'
              //, other svgs
    };

    return {
        restrict: 'E',
        link: function (scope, element, attr) {

            var icon, size;
            var render = function () {
                    icon = attr.icon;
                    var ss = icon.match(/ic_(.*)_([0-9]+)px.svg/m);
                    if (ss !== null) {
                        icon = ss[1];
                        size = ss[2];
                    }

                // size
                if (attr.size !== undefined)
                    size = attr.size;
                else if (size !== null)
                    size = 24;

                // render
                element.html('<svg xmlns="http://www.w3.org/2000/svg"  width="' + size + '" height="' + size + '" x="0px" y="0px" ' + shapes[icon]);
            };
            render();
        }
    };
});

Demo Plunker

Upvotes: 0

Related Questions