12

I'm trying to implement the facebook share button in my app, however I can't seem to get it to work on and idk why this is what I have so far.

html(/post/some-random-string)

<div id="fb-root"></div>
<meta property="og:site_name" content="App">
<meta property="og:url" content="/post/{{data.permalink}}">
<meta property="og:title" content="{{data.title}}">
<meta property="og:type" content="blog">
<meta property="og:image" content="https://i1.ytimg.com/vi/tIWPnxEpNQg/maxresdefault.jpg"> 
<meta property="og:description" content="{{data.preview}}">

<body >
<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&appId=580882498674160&version=v2.0";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
   // this facebook share button doesn't appear.
   <div class="fb-share-button" data-href="https://developers.facebook.com/docs/plugins/" data-type="button"></div>
   //so i manually make one.
  <a href="" ng-click='facebookShare();'>Share</a>
 </body>

controller.js

$scope.facebookShare= function(){
   return window.open('http://www.facebook.com/sharer/sharer.php?u='+encodeURIComponent(location.href), 'facebook_share', 'height=320, width=640, toolbar=no, menubar=no, scrollbars=no, resizable=no, location=no, directories=no, status=no');
 }

it works however it didn't read the meta tag i have written above on the html page instead it reads from my index page enter image description here

index page

<!DOCTYPE html>
<html ng-app='app'>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<noscript>
  <meta http-equiv="refresh" content="7">
    <style type="text/css">
      .pagecontainer {display:none;} 
    </style>
    <div class="pure-u-1 text-center">
    <title>Symsal- Oh no ! We need Javascript to work !</title>
    <h3> Please Enable javascript </h3>
    </div>
</noscript>
  <head>
  <title ng-bind='title'></title>
  // some css file 
  </head>
<body>
<div class='puretype'>
<div ng-controller="MasterCtrl">
<div id="layout">
    <!-- Menu toggle -->
    <a href="" id="menuLink" class=" white menu-link">
        <span></span>
    </a>
<div id='menu' class="pure-u-1">
   <div ng-bind-html="userView"></div> 
</div>
</div>
<div class="pure-g-r">
<div id="feed-container" class='pure-u-1 slide'ng-view=''></div>
</div>
</div>
</div>
// some javascript files 
</body>
</html>

facebook debugger enter image description here

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
John Lim
  • 3,019
  • 4
  • 31
  • 41
  • 1
    What does https://developers.facebook.com/debug say? What is the link to the page? – WizKid May 15 '14 at 05:14
  • @WizKid Hi, thanks for your reply. i have added facebook debugger result on the question – John Lim May 15 '14 at 05:21
  • Can you add the url too so I don't have to copy it from the picture? – WizKid May 15 '14 at 05:22
  • https://naalxofxay.localtunnel.me/post/r6I8eo7HxQ8 – John Lim May 15 '14 at 05:28
  • the URL may be different because it is an auto generator link from localtunnel but the page is the same – John Lim May 15 '14 at 05:29
  • Looking at view page source for that url doesn't show any og:...-tags at all. Do you see them when you do view page source? – WizKid May 15 '14 at 05:31
  • i got none too, it only show my index.html view instead of that particular post view, is it supposed how single page application behave ? – John Lim May 15 '14 at 05:33
  • Facebook doesn't execute Javascript when they load your page. They load the HTML and see if the tags are there. – WizKid May 15 '14 at 05:41
  • @WizKid yup i think that's the problem because i loaded view by using ng-view and the sharer only read the meta tag from the index page not the view i loaded by using ng-view. is there any way to solve this ? – John Lim May 15 '14 at 05:51

5 Answers5

17

What jackypan1989 said is true, you will have to use the absolute url. But one other thing that I'm pretty sure happens is that Facebook won't run your JavaScript code, thus the part

<meta property="og:url" content="/post/{{data.permalink}}">

will never get replaced with

<meta property="og:url" content="/post/the-page-that-was-shared">

This problem that you are having could also prevent Google from crawling your page.

We had the same problem, and we used https://prerender.io to get around it. You can use it on your own server, or use one of their free/paid services.

irukavina
  • 426
  • 2
  • 6
  • 1
    How does `prerender.io` knows when the page is ready? rendering the page with javascript is the easy part, but there are many AJAX call that a page mostly likely depends on, and you must know when AJAX call have been resolved – vsync Oct 29 '16 at 14:57
2

You already have a body defined around your ng-view. Then your view has its own body. So you are trying to inject a body inside of a body which isn't going to do what you want.

Notice that your controller does not control the HTML element that contains the Meta tags. It only controls code that it contains (a div within the body in your case).

You can add a controller to the HTML tag or you can use $rootScope.

Lots of answers to this here: How to dynamically change header based on AngularJS partial view?

In your controller that handles the ng-view: app.controller('MainControl', function ($rootScope, $scope, Config) { ... $rootScope.canonical = Config.domain; });

I needed to dynamically set a canonical link, but the principal for metas is the same. In your header: <link rel="canonical" ng-href="{{ canonical }}" />

You'll probably want to use ng-bind for a meta tag.

Community
  • 1
  • 1
Splaktar
  • 5,506
  • 5
  • 43
  • 74
2

I would add to the previous answers that prerender will solve crawling problems but facebook share is a bit different I think ( feel free to prove me wrong :) ). To avoid annoying {{}} you can define your own meta directive <meta meta-description> and use a template:

app.directive('metaDescription', [ 'metaData', function(metaData){
  return {
    restrict: 'A',
    replace: true,
    template: '<meta name="description" content="{{metaData.pageDesc}}">',
    link: function(scope,element){
      scope.metaData = metaData;


    }
  };
}]);

We are still figuring out SEO/sharing issues with angularJS here but that's what we currently use.

Alex C
  • 1,334
  • 2
  • 18
  • 41
0

In your codes, you should set up your absolute url on attr 'data-href' of fb-share-button.

For example:

<div class='fb-share-button' data-href='https://yourabsoluteurl.com' data-type='button'>
</div>
jackypan1989
  • 2,786
  • 1
  • 13
  • 11
0

I made it work using express. There may be some gaps in this, so if anyone tries it, feel free to fill in the gaps in the comments and I'll update...

I have both express and react running in two different consoles locally. For some reason, I only needed to run node on the express file in prod. Do whatever you need to to get it running. This will forward the request to the react server.

app.get('*', function(req, res) {
    res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

Then I have a route for the pages that I share that looks something like this.

app.get('/details/:itemId', function(req, res) {
    const fileName = path.join(__dirname, 'build', `${req.params.itemId}.html`);
    var fileContents = fs.readFileSync(path.join(__dirname, 'build', 'index.html'), 'utf8');
    fileContents = fileContents.replace("og tags", "new values");
    fs.writeFileSync(fileName, fileContents);
    res.sendFile(fileName);
});

You probably will want to search for the file and serve that up first if it exists so you aren't having problems with multiple clients writing to the same file at the same time in a high volume environment. Or better yet, do it in memory. Remember, order counts in express, so you really need to reverse the order of these two functions in your express file.

Michael
  • 1,177
  • 15
  • 15