Question

I'm using angularjs and wanted to add share buttons to my pages for different social networking sites. So far I've found Angular-socialshare and Socialitejs but don't know which one to choose or if other really good ones exist, that I don't even know of.

Was it helpful?

Solution

Here is an alternative to angular-socialshare (has share counter) that is currently the most popular/active on GitHub:

http://github.com/esvit/angular-social

Here is a simplified share button (no counter). This directive uses Font Awesome as a dependency.

http://github.com/tinacious/angular-easy-social-share


A note about metadata scraping and single page applications

Keep in mind that social network crawlers, which scrape HTML metadata for rich snippets (like OpenGraph links to images and descriptions), do not evaluate JavaScript. This can render certain meta tags in the header as {{bracketed}} expressions in a share box rather than dynamically loaded content... Assuming you have metadata that is loaded dynamically with AngularJS.

Check out this article about sharing rich snippets with Angular should you have that requirement: http://www.michaelbromley.co.uk/blog/171/enable-rich-social-sharing-in-your-angularjs-app

OTHER TIPS

there is very easy solution that works fine with me,

you can rename you index.html to index.php

and include a php page that have a code to parse URL and based on the URL Parameters you can add your Title and description and image for twitter and facebook

here is the code of php page included in my index

<?

function curPageURL() {
$pageURL = 'http';
if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";}
$pageURL .= "://";
if ($_SERVER["SERVER_PORT"] != "80") {
$pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
} else {
$pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
}
return $pageURL;
}




$parse = parse_url(curPageURL());

$urlArray =  explode("/",$parse['path']);

$urlPage = $urlArray[2];

if($urlPage == "profile"){ 
$image = "profile-img.jpg";
$title = "Title of the page ";
$desc = "Description of Profile the page ";
$websiteUrl = "Http://example.com";
}elseif($urlPage == "news"){ 
$title = "Title of the News page ";
$desc = "Description of the page ";
$websiteUrl = "Http://example.com"; 
}

?>


<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title><? echo $title; ?></title>


<meta property="twitter:card" content="summary" />
<meta property="twitter:site" content="<? echo $websiteUrl; ?>" />
<meta property="twitter:title" content="<? echo $title; ?>" />
<meta property="twitter:description" content="<? echo $description; ?>" />
<meta property="twitter:image" content="<? echo $image; ?>" />
<meta property="twitter:url" content="<? echo curPageURL(); ?>" />

<meta property="og:title" content="<? echo $title; ?>" />
<meta property="og:description" content="<? echo $description; ?>" />
<meta property="og:image" content="<? echo $image; ?>" />
<meta property="og:type" content="article" />
<meta property="og:site_name" content="<? echo $website_name; ?>" />
<meta property="og:url" content="<? echo curPageURL(); ?>" />

Considering sinisterOrange's answer I'd like to add that there's some vital pieces of information about Michael Bromley's elegant solution.

In order to have multiple conditions for redirecting your urls into a script that will render the meta-tags correctly you must apply the condition multiple times for each rule.

And finally you'd have to make a negative condition for your app access.

<ifModule mod_rewrite.c>
    RewriteEngine On

    RewriteCond %{HTTP_USER_AGENT} (facebookexternalhit/[0-9]|Twitterbot|Pinterest|Google.*snippet)
    RewriteRule ^post/([A-Za-z0-9-]+)/([0-9-]+)$ http://www.example.com/api/renderMetaTags/post/$2 [P,L]

    RewriteCond %{HTTP_USER_AGENT} (facebookexternalhit/[0-9]|Twitterbot|Pinterest|Google.*snippet)
    RewriteRule ^location/([A-Za-z0-9-]+)/([0-9-]+)$ www.example.com/api/renderMetaTags/location/$2 [P,L]

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !index

    #this condition for crawlers not to interfere with normal access
    RewriteCond %{HTTP_USER_AGENT} !(facebookexternalhit/[0-9]|Twitterbot|Pinterest|Google.*snippet)

    #this rule for html5 mode and friendly urls without the #
    RewriteRule ^(.*)$ /#/$1 [L]

</ifModule>

That'd be it. I know it's a little bit off-topic but I lost valuable time arriving at this solution.

Consider this solution as it worked for me using mvc 5 with angular js

In Index page copy this code

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.12/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
<script src='test.js'></script>
<script src="http://platform.twitter.com/widgets.js"></script>
</head>
<body ng-app='testing'>
<div ng-controller='temp'>
    <div facebook class="facebookShare" data-title='{{title}}' data-picture-url='http://i.imgur.com/WACv9Cl.jpg' data-url='{{url}}' data-shares='shares' data-callback='callback'>{{ shares }}  </div>   
 <br />
    <a twitter data-count='horizontal' data-url='{{url}}' data-size="medium" data-text='{{text}}'></a>
    <br /><br />
    <div class="linkedinShare" linkedin data-url='{{url}}' data-title='{{title}}' data-summary="{{text}}" data-shares='linkedinshares'>{{linkedinshares}}</div>
    <br /><br />
    <div gplus data-size="tall" data-annotation="bubble" data-href='{{url}}' data-action='share'></div>   
</div>
</body>
</html>

In script.js write this below mentioned code

angular.module('testing', ['djds4rce.angular-socialshare'])
.run(function ($FB) {
$FB.init('Facebook App Id');
});

angular.module('testing').controller('temp', function ($scope, $timeout)      {

$timeout(function () {
    $scope.url = 'http://google.com';
    $scope.text = 'testing share';
    $scope.title = 'title1'
}, 1000)
$timeout(function () {
    $scope.url = 'https://www.youtube.com/watch?v=wxkdilIURrU';
    $scope.text = 'testing second share';
    $scope.title = 'title2';
}, 1000)

$scope.callback = function (response) {
    console.log(response);   
}
});

This code is for the directive

angular.module('djds4rce.angular-socialshare', [])
.factory('$FB', ['$window', function ($window) {
    return {
        init: function (fbId) {
            if (fbId) {
                this.fbId = fbId;
                $window.fbAsyncInit = function () {
                    FB.init({
                        appId: fbId,
                        channelUrl: 'app/channel.html',
                        status: true,
                        xfbml: true
                    });
                };
                (function (d) {
                    var js,
                        id = 'facebook-jssdk',
                        ref = d.getElementsByTagName('script')[0];
                    if (d.getElementById(id)) {
                        return;
                    }

                    js = d.createElement('script');
                    js.id = id;
                    js.async = true;
                    js.src = "//connect.facebook.net/en_US/all.js";

                    ref.parentNode.insertBefore(js, ref);

                }(document));
            } else {
                throw ("FB App Id Cannot be blank");
            }
        }
    };

}]).directive('facebook', ['$http', function ($http) {
    return {
        scope: {
            callback: '=',
            shares: '='
        },
        transclude: true,
        template: '<div class="facebookButton">' +
            '<div class="pluginButton">' +
            '<div class="pluginButtonContainer">' +
            '<div class="pluginButtonImage">' +
            '<button type="button">' +
            '<i class="pluginButtonIcon img sp_plugin-button-2x sx_plugin-button-2x_favblue"></i>' +
            '</button>' +
            '</div>' +
            '<span class="pluginButtonLabel">Share</span>' +
            '</div>' +
            '</div>' +
            '</div>' +
            '<div class="facebookCount">' +
            '<div class="pluginCountButton pluginCountNum">' +
            '<span ng-transclude></span>' +
            '</div>' +
            '<div class="pluginCountButtonNub"><s></s><i></i></div>' +
            '</div>',
        link: function (scope, element, attr) {
            attr.$observe('url', function () {
                if (attr.shares && attr.url) {
                    $http.get('https://api.facebook.com/method/links.getStats?urls=' + attr.url + '&format=json').success(function (res) {
                        var count = res[0] ? res[0].total_count.toString() : 0;
                        var decimal = '';
                        if (count.length > 6) {
                            if (count.slice(-6, -5) != "0") {
                                decimal = '.' + count.slice(-6, -5);
                            }
                            count = count.slice(0, -6);
                            count = count + decimal + 'M';
                        } else if (count.length > 3) {
                            if (count.slice(-3, -2) != "0") {
                                decimal = '.' + count.slice(-3, -2);
                            }
                            count = count.slice(0, -3);
                            count = count + decimal + 'k';
                        }
                        scope.shares = count;
                    }).error(function () {
                        scope.shares = 0;
                    });
                }
                element.unbind();
                element.bind('click', function (e) {
                    FB.ui({
                        method: 'share',
                        href: attr.url
                    }, function (response) {
                        if (scope.callback !== undefined && typeof scope.callback === "function") {
                            scope.callback(response);
                        }
                    });
                    e.preventDefault();
                });
            });
        }
    };
}]).directive('facebookFeedShare', ['$http', function ($http) {
    return {
        scope: {
            callback: '=',
            shares: '='
        },
        transclude: true,
        template: '<div class="facebookButton">' +
            '<div class="pluginButton">' +
            '<div class="pluginButtonContainer">' +
            '<div class="pluginButtonImage">' +
            '<button type="button">' +
            '<i class="pluginButtonIcon img sp_plugin-button-2x sx_plugin-button-2x_favblue"></i>' +
            '</button>' +
            '</div>' +
            '<span class="pluginButtonLabel">Share</span>' +
            '</div>' +
            '</div>' +
            '</div>' +
            '<div class="facebookCount">' +
            '<div class="pluginCountButton pluginCountNum">' +
            '<span ng-transclude></span>' +
            '</div>' +
            '<div class="pluginCountButtonNub"><s></s><i></i></div>' +
            '</div>',
        link: function (scope, element, attr) {
            attr.$observe('url', function () {
                if (attr.shares && attr.url) {
                    $http.get('https://api.facebook.com/method/links.getStats?urls=' + attr.url + '&format=json').success(function (res) {
                        var count = res[0] ? res[0].total_count.toString() : 0;
                        var decimal = '';
                        if (count.length > 6) {
                            if (count.slice(-6, -5) != "0") {
                                decimal = '.' + count.slice(-6, -5);
                            }
                            count = count.slice(0, -6);
                            count = count + decimal + 'M';
                        } else if (count.length > 3) {
                            if (count.slice(-3, -2) != "0") {
                                decimal = '.' + count.slice(-3, -2);
                            }
                            count = count.slice(0, -3);
                            count = count + decimal + 'k';
                        }
                        scope.shares = count;
                    }).error(function () {
                        scope.shares = 0;
                    });
                }
                element.unbind();
                element.bind('click', function (e) {
                    FB.ui({
                        method: 'feed',
                        link: attr.url,
                        picture: attr.picture,
                        name: attr.name,
                        caption: attr.caption,
                        description: attr.description
                    }, function (response) {
                        if (scope.callback !== undefined && typeof scope.callback === "function") {
                            scope.callback(response);
                        }
                    });
                    e.preventDefault();
                });
            });
        }
    };
}]).directive('twitter', ['$timeout', function ($timeout) {
    return {
        link: function (scope, element, attr) {
            var renderTwitterButton = debounce(function () {
                if (attr.url) {
                    $timeout(function () {
                        element[0].innerHTML = '';
                        twttr.widgets.createShareButton(
                            attr.url,
                            element[0],
                            function () { }, {
                                count: attr.count,
                                text: attr.text,
                                via: attr.via,
                                size: attr.size
                            }
                        );
                    });
                }
            }, 75);
            attr.$observe('url', renderTwitterButton);
            attr.$observe('text', renderTwitterButton);
        }
    };
}]).directive('linkedin', ['$timeout', '$http', '$window', function ($timeout, $http, $window) {
    return {
        scope: {
            shares: '='
        },
        transclude: true,
        template: '<div class="linkedinButton">' +
            '<div class="pluginButton">' +
            '<div class="pluginButtonContainer">' +
            '<div class="pluginButtonImage">in' +
            '</div>' +
            '<span class="pluginButtonLabel"><span>Share</span></span>' +
            '</div>' +
            '</div>' +
            '</div>' +
            '<div class="linkedinCount">' +
            '<div class="pluginCountButton">' +
            '<div class="pluginCountButtonRight">' +
            '<div class="pluginCountButtonLeft">' +
            '<span ng-transclude></span>' +
            '</div>' +
            '</div>' +
            '</div>' +
            '</div>',
        link: function (scope, element, attr) {
            var renderLinkedinButton = debounce(function () {
                if (attr.shares && attr.url) {
                    $http.jsonp('https://www.linkedin.com/countserv/count/share?url=' + attr.url + '&callback=JSON_CALLBACK&format=jsonp').success(function (res) {
                        scope.shares = res.count.toLocaleString();
                    }).error(function () {
                        scope.shares = 0;
                    });
                }
                $timeout(function () {
                    element.unbind();
                    element.bind('click', function () {
                        var url = encodeURIComponent(attr.url).replace(/'/g, "%27").replace(/"/g, "%22")
                        $window.open("//www.linkedin.com/shareArticle?mini=true&url=" + url + "&title=" + attr.title + "&summary=" + attr.summary);
                    });
                });
            }, 100);
            attr.$observe('url', renderLinkedinButton);
            attr.$observe('title', renderLinkedinButton);
            attr.$observe('summary', renderLinkedinButton);
        }
    };
}]).directive('gplus', [function () {
    return {
        link: function (scope, element, attr) {
            var googleShare = debounce(function () {
                if (typeof gapi == "undefined") {
                    (function () {
                        var po = document.createElement('script');
                        po.type = 'text/javascript';
                        po.async = true;
                        po.src = 'https://apis.google.com/js/platform.js';
                        po.onload = renderGoogleButton;
                        var s = document.getElementsByTagName('script')[0];
                        s.parentNode.insertBefore(po, s);
                    })();
                } else {
                    renderGoogleButton();
                }
            }, 100);
            //voodo magic
            var renderGoogleButton = (function (ele, attr) {
                return function () {
                    var googleButton = document.createElement('div');
                    var id = attr.id || randomString(5);
                    attr.id = id;
                    googleButton.setAttribute('id', id);
                    element.innerHTML = '';
                    element.append(googleButton);
                    if (attr.class && attr.class.indexOf('g-plusone') != -1) {
                        window.gapi.plusone.render(id, attr);
                    } else {
                        window.gapi.plus.render(id, attr);
                    }
                }
            }(element, attr));
            attr.$observe('href', googleShare);
        }
    };
}]);

function debounce(func, wait, immediate) {
var timeout;
return function () {
    var context = this,
        args = arguments;
    var later = function () {
        timeout = null;
        if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
};
};
function randomString(len, an) {
an = an && an.toLowerCase();
var str = "",
    i = 0,
    min = an == "a" ? 10 : 0,
    max = an == "n" ? 10 : 62;
for (; i++ < len;) {
    var r = Math.random() * (max - min) + min << 0;
    str += String.fromCharCode(r += r > 9 ? r < 36 ? 55 : 61 : 48);
}
return str;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top