How to update the meta tag in ionic dynamically? So that it can work in facebook social sharing - ionic-framework

In the ionic project, there is only one head section where we write all the meta tag that is in the index.html page. For example, to make the Facebook sharing work perfectly we need this meta tag given bleow:
<meta property="og:title" content="Title">
<meta property="og:description" content="description">
<meta property="og:image" content="Image Url you want to show">
<meta property="og:url" content="http://yourUrl.com">
So how can we update this meta tag from other pages? For example, if we go to a news detail page the meta tag of that page will be changed accordingly. So how can I achieve this in my Ionic4 with angular project?

I believe that you can do it in a way similar to this:
var link = document.createElement('meta');
link.setAttribute('property', 'og:url');
link.content = document.location;
document.getElementsByTagName('head')[0].appendChild(link);

In my existing Ionic 4 project, I want to use Angular Universal but I got into so many errors. So I created a new project using Ionic 5. And move all my previous work to the new Ionic 5. I follow these steps to add Angular Universal to my project.
At first, create an app and update it to the latest version of Angular using these commands.
ionic start myApp blank --type angular
cd myApp
ng update #angular/core #angular/cli
npm install #angular/animations
Then add Express engine for Angular Universal using this command.
ng add #nguniversal/express-engine
Then you need to install the #ionic/angular-server module using this command.
npm install #ionic/angular-server#dev
For testing in the localhost, your server-side rendering is working correctly you need to use this command.
npm run dev:ssr
For more detailed information on how to setup Angular Universal for server-side-rendering you can see the ionic blog link SSR with Angular Universal And Ionic.
After setting, angular universal you need to add title, add, or update meta tag. You can follow my sample code given below:
import { Component, OnInit} from '#angular/core';
import { Title, Meta } from '#angular/platform-browser';
#Component({
selector: 'app-sample',
templateUrl: './sample.page.html',
styleUrls: ['./sample.page.scss'],
})
export class SamplePage implements OnInit {
constructor(private titleService: Title, private meta: Meta) { }
ngOnInit() {
this.titleService.setTitle("Your Title");
this.meta.updateTag({ property: 'og:url', content:'http://yoururl.com'});
this.meta.updateTag({ property: 'og:title', content:"Your Title" });
this.meta.updateTag({ property: 'og:image', content: "your image link"});
this.meta.updateTag({ property: 'og:description', content: "description"});
}
}
Now your social share will work perfectly. Because when it crawls not it will get the metatag with data. You need to update the meta tag based on the social share you want to add.

I got this working last week using Renderton as described in this post by Jeff Delaney. You'll still need to setup server side rendering (SSR) through this artcle. Lastly, make sure none of your code references the window, which will break SSR and Rendetron.

One can use ionic's pre build hooks to modify the index.html after building. Add hooks in your ionic.config.json file
{
"name": "xxxx",
"integrations": {
"capacitor": {}
},
"type": "vue",
"id": "xxxxx",
"hooks": {
"build:after": "./deploy/after-build.js"
}
}
and then in your project folder (top level) create folder deploy with file after-build.js with following content:
var fs = require('fs')
module.exports = (ctx) => {
const index = `${ctx.project.dir}/dist/index.html`;
fs.readFile(index , 'utf8', (err, html) => {
const meta = '<meta name="NEW-META" />';
html = html.replace(/<meta name="OLD-META".*?">/, meta);
fs.writeFile(index, html, 'utf8', err => err && console.log( err ));
});
};

Related

Facebook plugins (like button, page plugin, comments...) in Gatsby

I'm digging up how to implement Facebook plugins into Gatsby. I'm dealing with 3 issues:
1) Insert Facebook script into header which then walk through the page and render plugins (renders XFBML markup).
It can be done by manual inserting right in html.js file or just using plugin. Both do the work.
2) Put FB code (XFBML markup) in place where it is desired to render plugin.
Since in Gatsby pages are building in React it's needed to use dangerouslySetInnerHTML
example:
<div
dangerouslySetInnerHTML={{
__html: '
<div class="fb-like"
data-href="https://localhost/"
data-layout="standard"
data-action="like"
data-show-faces="true">
</div>
'
}}
/>
And whoala! Plugin is there ...BUT! This happens only when page is refreshed and because Gatsby is Single-Page Application when route is changed nothing is rendering.
3) Call FB.XFBML.parse() on page where is at least one Facebook plugin.
When I call this in browser plugins render but how to call it automatically in page? Moreover FB is object on global level which is not accessible from inside of page.
React Facebook package may work.
Example code:
import React from "react";
import { FacebookProvider, Like } from 'react-facebook';
import { APP_ID } from "./constants";
import { Location } from "#reach/router";
export default (props) => {
return (
<FacebookProvider appId={APP_ID}>
<Location>
{({ location }) => (
<Like
href={location.href}
colorScheme="light"
showFaces={false}
share
layout="button_count"
{...props}
/>
)}
</Location>
</FacebookProvider>
);
}

Send user to page on mobile app when clicking email link

I have just started an Ionic 2 mobile app.
I am setting up an update password process where a user can enter their email, click a "send password update email" button which then emails them a link. They can click that link which takes them to a page where they can update their password.
How do I send them a link in their email that when clicked on will open up the app and take them to a specific page?
Even more complicated is that I have a web app also. So if I'm sending them an email, should I show update password on website and update password on mobile app links? Or should I just add a link to the website?
In order to open the mobile app from a link, you need to integrate a cordova plugin called cordova-plugin-customurlscheme. With this plugin you can register a custom url "protocol" that is unique to your app (eg. myAwesomeApp://register?token=123). After installing the plugin with your custom url, clicking on any link starting with myAwesomeApp:// will open your app and also trigger a function hooked on the window object called handleOpenUrl which accepts the url as param. Inside there you can do your routing, depending on the url param.
let self = this;
(<any>window).handleOpenURL = function handleOpenURL(url) {
setTimeout(() => {
if (url && url.indexOf('\register') !== -1) {
let token = URLHelper.getParameterByName(url, 'token');
self.setAsRoot(ConfirmEmailPage, { activationToken: token });
}
}, 0);
};
As for dealing with your web app, what you could do is the following (this is what I am currently doing):
Host online a page (say www.myAwesomeWebsite.com/register?token=123) that checks to see if the user is coming from a mobile device (iOS or Android more specifically). If so on page load redirect them to your myAwesomeApp://register?token=123 link and have a button saying install app from app store with a link to your mobile app. If the user has the app, the app will be opened by the redirect, if they don't they will get an alert saying link cannot be found or sth and after clicking ok they will see the install App from app store button. If the user is not coming from a mobile device, just redirect them to your web app myAwesomeWebApp.com/register?token=123.
Another option is to use a third party service for deep linking like branch
Hope that helps.
EDIT: Since I posted this answer Ionic team has come with their own plugin for deep linking that kind of simplifies some of the hooking up inside your app. Their detailed blog post can be found here. In essence you install their plugin:
cordova plugin add ionic-plugin-deeplinks --variable URL_SCHEME=ionichats --variable DEEPLINK_SCHEME=https --variable DEEPLINK_HOST=ionic-hats.com
and then hook to it like so:
import {Component, ViewChild} from '#angular/core';
import {Platform, Nav, ionicBootstrap} from 'ionic-angular';
import {Deeplinks} from 'ionic-native';
import {AboutPage} from './pages/about/about';
import {HatDetailPage} from './pages/hat/hat';
#Component({
template: '<ion-nav [root]="rootPage"></ion-nav>',
})
class MyApp {
#ViewChild(Nav) nav:Nav;
constructor(private _platform: Platform) {}
ngAfterViewInit() {
this._platform.ready().then(() => {
Deeplinks.routeWithNavController(this.nav, {
'/about-us': AboutPage,
'/hats/:hatId': HatDetailPage
});
});
}
});
ionicBootstrap(MyApp);
Note that although this improves the plugin interfacing a bit, it does not change the fact that you have to use some other mechanism to handle deep links in conjunction with your web app.

How to display dynamic page description in a shared angularJS page (via google +1 for instance)

I am trying enable the metas in our app for google+ and facebook +1's and I get either nothing, the url of the page, or {{pageDesc}} in the post. Right now I am using a directive that dynamically sets the meta description:
HTML:
<meta meta-description>
DIRECTIVE:
app.directive('metaDescription', [ 'metaData', function(metaData){
return {
restrict: 'A',
replace: true,
template: '<meta name="description" content="{{description}}">',
link: function(scope,element){
scope.metaData = metaData;
scope.description = scope.metaData.pageDesc;
}
};
}]);
When doing this, the google api does not recognize the title and description and just sets the url of the current page and the url of the site as title/description.
I was poking around with prerender.io but I had to disable it because it made the +1 plugin crash.
You have to set those values in the HTML before you render the document. The Facebook/Google/etc bots that crawl the pages don't usually execute JavaScript.

Chrome packaged application - downloading file from Webview

I am working on getting an existing Ajax style web application functional as a Chrome packaged app. The Ajax app is running in a Webview inside the packaged app and is mostly working great.
The Ajax app allows users to upload documents using standard HTML 5 upload and drag/drop. Uploads work fine but downloads are not working.
This is a simplified sample of the logic in the Ajax app. It uses Javascript to handle the click event, performs some logic, and then eventually triggers the download by setting the location of a hidden IFrame.
<html>
<head>
<script type="text/javascript">
function downloadFile(url) {
window.frames['dataTransfer'].location = url;
}
</script>
</head>
<body>
Google<br/>
Download PDF<br/>
Download PDF JS<br/>
<iframe name="dataTransfer" style="width: 0; height: 0; border: none;"></iframe><br/>
</body>
</html>
If you run this in a standard Chrome tab all 3 links work fine. However in a Chrome App only the first 2 links work - clicking the 3rd link does nothing. In the network section of the Developer tools it actually appears to start the download but then is quickly cancelled.
The manifest of the Chrome app allows Webview and the relevant domains involved.
{
"manifest_version": 2,
"name": "Test Download",
"version": "0.1.0",
"permissions": [
"webview",
"<DOMAIN OF THE SAMPLE PAGE ABOVE>",
"https://s3.amazonaws.com/"
],
"app": {
"background": {
"scripts": ["background.js"]
}
},
"icons": {},
"minimum_chrome_version": "28"
}
The Chrome App has some simple newwindow handling in it as well.
window.onload = function() {
var webview = document.querySelector('#app-webview');
webview.src = '<URL TO SAMPLE PAGE ABOVE>';
webview.addEventListener('newwindow', function(e) {
e.preventDefault();
e.stopPropagation();
window.open(e.targetUrl);
});
};
Any suggestions on how to get downloads working (hopefully without requiring significant changes to the Ajax app)?
File downloads from the webview guest are gated by a permissionrequest event per download attempt. The default response is to deny download permission.
Note: The download permissionrequest will not land until Chrome 30 now, and it appears that documentation has not yet been made available. It is generally a stable API though, and it is unlikely to change between now and then.
In order to override this behavior, you need to handle the event and explicitly allow the download to happen. As an example:
var webview = document.querySelector('#app-webview');
webview.addEventListener('permissionrequest', function(e) {
if (e.permission === 'download') {
e.request.allow();
}
});
The event includes additional information (such as the download URL in e.url) in case you want to further filter your grants.
Be aware that this will only permit the download to happen using the regular Chrome file download experience, which isn't necessarily what you'll want from within a packaged app. Your options are limited until the chrome.downloads API is made available to apps.
One possibility is to deny the download request, grab the URL from the event, and manually manage the download process with XHR, the fileSystem API, and whatever UX you want to build.

How to show simple REST data in from Ember starter kit?

I downloaded the ember starter kit and want to show a simple REST API data to see how Ember works.
From videos and tutorials I found that there is a model hook that can be used to inject data.
So I did the following:
App.Router = Ember.Router.extend({
model: function ({
return $.getJSON("https://api.foursquare.com/v2/users/self?oauth_token=TOKENHERE&v=20130723");
}),
root: Ember.Route.extend({
index: Ember.Route.extend({
route: '/'
})
})
})
And added the following in my index.html
<script type="text/x-handlebars" data-template-name="application">
{{title}}
</script>
However, this didn't work. When I go to index.html I don't see anything there. Additionally, under Network tab of Inspect Element, I don't see any network requests being made to the REST API.
What am I doing wrong? Also, for sample purpose I would simply like to have a data.json json file that will contain some json data. However, I read that Ember lacks support to read a file, thats why I'm trying a sample rest api provided by foursquare.
Is there a way to read a json file using ember? I'm running this simply on my browser without a server.
That looks like it should work. Here is an example using a different API but using the same structure:
JavaScript:
App = Ember.Application.create();
App.Router.map(function() {
// put your routes here
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return $.getJSON("https://api.github.com/repos/emberjs/ember.js/stats/contributors");
}
});
Templates:
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
Ember.js repository contributors
<ul>
{{#each user in controller}}
<li>{{user.author.login}}</li>
{{/each}}
</ul>
</script>
JSBin example