My FeedDiscussionsHeadless CMS
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more

$compile in angularJS

monis's photo
monis
·Apr 2, 2017

Hi,

I am building feeds like pinterest, having cards with different data and different permissions, structure is something like this :

(1)Main directive structure

(1.1)can have image,video,audio

(1.2)some permissions like (edit,delete,hide)

also having infinite scroll, so the structure I made is something like this

<ul>
<li ng-repeat="cardsInfo in feeds">
 <my-card-directive  card-data="{{cardsInfo.type}}" media-feed-type="{{cardsInfo.feed_type}}" card-id="{{$index}}"></my-card-directive>
</li>
</ul>
.directive('myCardDirective', ['$compile', '$templateRequest', function($compile, $templateRequest) {
        return {
            restrict: 'E',
            link: function(scope, elem, attrs) {
                function uploadTemplate(templateName) {
                    $templateRequest('templates/home/templates/feedCards/' + templateName).then(function(html) {
                        var template = angular.element(html);
                        elem.html($compile(template)(scope));
                    })
                }
                switch (attrs.cardData) {
                    case 'type1':
                        uploadTemplate('type1.html')
                        break;
                    case 'type2':
                        uploadTemplate('type2.html')
                        break;
                    case 'type3':
                        if (attrs.mediaFeedType == '') {
                            uploadTemplate('type3.html');
                        } else {
                            uploadTemplate('type3_1.html');
                        }
                        break;
                    case 'type4':
                    case 'type5':
                        uploadTemplate('type4.html');
                        break;
                    case 'type5':
                    case 'type6':
                    case 'type7':
                        uploadTemplate('type5.html')
                        break;
                    case 'type8':
                        uploadTemplate('type6.html')
                        break;
                    case 'type9':
                        uploadTemplate('type7.html');
                        break;
                    default:
                        uploadTemplate('default.html')
                        break;
                }
            }
        }
    }])

'type(anynumber).html' contains

<!-- inner directve 1 -->
<figure check-media-type media="{{cardsInfo.file_type}}">
<third-party-video ng-if="on-some-condiition"><third-party-video>
</figure>
<!-- some filters and other info -->
    <div class="foot">
       <!-- some footer styles -->

                <!-- inner directive 2 -->
                <div class="dropdown-menu dropdown-menu-default" check-feed-card owner-detail="{{cardsInfo.ownerPermission}}" content-type="{{cardsInfo.content_type}}"></div>
            </div>
        </div>
    </div>
</div>
<!-- inner directive 1  definition-->
.directive('checkMediaType', ['$compile', function($compile, filter) {
        return {
            restrict: 'A',
            link: function(scope, elem, attrs) {

                var embedUrl = angular.element('<third-paty-embed-video  controls="1" width="100%" ></third-party-embed-video>');
                var addImage = angular.element('<img  alt="" />');
                var addAudio = angular.element('<audio controls><source   type="audio/ogg"></audio>');
                switch (attrs.media) {
                    case 'image':
                        var imgsrc = thumbnail(attrs.mediaFile)
                        addImage.attr('src', imgsrc);
                        elem.html($compile(addImage)(scope));
                        break;
                    case 'video':
                        if ('some_conditions_check') {
                            embedUrl.attr('data-ng-href', attrs.isEmbed);
                            elem.html($compile(embedUrl)(scope));
                        }
                        break;
                    case 'audio':

                        break;
                    case '':
                        embedUrl.attr('data-ng-href', attrs.isEmbed);
                        elem.html($compile(embedUrl)(scope));
                        break;
                }
            }
        }
    }])
<!-- inner directive 2  definition-->
.directive('checkFeedCard', ['[some services injected]', '$compile', function([services injected], $compile) {
        return {
            restrict: 'A',
            replace: true,
            transclude: true,
            link: function(scope, elem, attrs) {
                scope.setName;
                var details = JSON.parse(attrs.ownerDetail);
                var editMyPost = angular.element('<p class="set-p-margin"><a href="">Edit this {{setName}}</a></p>');
                var deleteMyPost = angular.element('<p class="set-p-margin"><a href="" ng-click="Deletethis(cardsInfo,$index)">Delete this {{setName}}</a></p>');
                var otherPosts = angular.element('<p class="set-p-margin"><a href="" ng-click="hideFeeds(cards)">Hide feeds from this {{setName}}</a></p>');
                var userRedirectState;
                var allowDeleteMyPost = false;

                if (some_condition_checks) {
                    switch (attrs.contentType) {
                        case 'type-1':
                            userRedirectState = "type-1-RedirectStateAdded";
                            scope.setName = attrs.contentType;
                            break;
                        case 'type-2':
                            userRedirectState = 'type-2-RedirectStateAdded'
                            scope.setName = attrs.contentType;
                            break;

                        case 'type-3':
                            userRedirectState = 'type-3-RedirectStateAdded'
                            scope.setName = attrs.contentType;
                            break;
                            .
                            .
                            .
                            .
                            .


                        case 'type-n':
                            scope.setName = attrs.contentType;
                            userRedirectState = 'type-N-RedirectStateAdded';
                            break;

                    }
                    editMyPost.children(":first").attr('ui-sref', userRedirectState);
                    elem.html($compile(editMyPost)(scope));
                    if (allowDeleteMyPost) {
                        elem.append($compile(deleteMyPost)(scope));
                        allowDeleteMyPost = false;
                    }
                } else {
                    scope.setName = detectUser.detectUserType(details.user_type);
                    if (some_condition_checks) {
                        elem.html($compile(otherPosts)(scope));
                    }
                }
            }
        }
    }])

Problem: In initial cases when feeds were few(especially images), all were good, no lags but as soon number increased with variety of data (audio, video,embedded url's) it's showing heavy lag with application got crashed in few feeds only (around 40-50), when checked for watchers it showed around 3k watchers, which is definitely wrong.

Is $compile cost heavy for such a case? because of infinite scroll fetching more data. Any valuable suggestion for performance can be improved or in approach. My approach was to divide it into different independent components, may be I have not used $compile properly or is it excessive usage in this scenario.

PS : I also tried to change all 2-way binding to single binding, which are only to display information.

using this library for grid generation : ignitersworld.com/lab/angulargrid

Thanks.