7
\$\begingroup\$

I have learned the question of solving Angular app optimization for search engines, and was frustrated that the most recommended option is prerendering HTML.

After some time spent, I suggested to create a directive that will load the bot after rendering templates or update scope.

Directive:

angular.module('test', []).directive('seoBot', ['$timeout', function($timeout){

    return {

        link: function($scope, element, attrs) {

            //publish event 
            $scope.$on('runbot', function(){

                //hint for start after render
                $timeout(function () {

                    //find previos google's bot
                    var googleBot = document.getElementById('googleBot');

                    //if found - remove
                    if(googleBot) googleBot.parentNode.removeChild(googleBot);

                    //this is standard code from GA, but with ID "googleBot"
                    (function(i,s,o,g,r,a,m){
                        i['GoogleAnalyticsObject']=r;
                        i[r]=i[r]||function(){
                            (i[r].q=i[r].q||[]).push(arguments)
                        },i[r].l=1*new Date();
                        a=s.createElement(o),
                        m=s.getElementsByTagName(o)[0];
                        a.id="googleBot";
                        a.async=1;
                        a.src=g;
                        m.parentNode.insertBefore(a,m);
                    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

                    ga('create', 'UA-46685745-1', 'rktdj.com');
                    ga('send', 'pageview');

                    //log that bot is loaded
                    console.log("seo-bot loaded");

                    //check page to be rendered completely
                    console.log(document.body.innerHTML);

                }, 0, false);

            });

        }

    };

}]);

In controller:

//get some data from server and update scope
$http.get(GLOBAL.api.SERVER_PATH + GLOBAL.api.facultiesByCourse + s_id)
        .success(function (data) {

            $scope.courses = data;
            console.dir($scope.courses);

            //broadcast event to seo-bot
            $scope.$broadcast('runbot');

        } );

seo-bot tag in the bottom of template:

    <div class="well" id="courseList">

        <!-- some template code -->

    </div>

    <div seo-bot></div>

It works, and the bot loads every time when template have update or route changed. I can check that all elements with data was rendered before.

But... will this solution really work? Will Google bot correctly correlate rendered page with the domain? Can I be banned for this?

\$\endgroup\$
  • \$\begingroup\$ Do you make the difference between the google bot and google analytics? The googlebot (search engine) is not executing the javascript (at least most of the time it is not...). This is why you need to pre-render the page if the request comes from the google bot. If you are talking about google analytics then alright your solution will work. Though I would suggest you to take a look at this project luisfarzati.github.io/angulartics. It does exactly what you are trying to do and even more. \$\endgroup\$ – jackdbernier Mar 19 '14 at 20:22
  • \$\begingroup\$ Wawaweewa it's a very nice! \$\endgroup\$ – pilau Aug 31 '14 at 13:58
2
\$\begingroup\$

As you found yourself, this has to work.

I only have 2 minor nitpickings:

  • Do not use console.log() in production code..
  • You are not using element and attrs, you might as well declare function($scope)

Very nice code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.