vue-meta => How to change the header information - vuejs2

I have a nuxtjs project with a page opening on a url like server\posts\id. On this page I have added head information to influence the meta tags. However, some tags are post specific and need to be filled dynamically. This only seems possible after you have data loaded in mounted. How can I add the meta maniplulation to mounted?

It seems you need an extra 'data' property. If you use this in the header, and update it later it will change the meta information.

Right way to get meta from api is: using fetch method
async fetch({ store, params }) {
await store.dispatch('modules/item/get_item', params.article)
},
Use Computed :
computed: {
...mapState('modules/item', {
Item: (state) => state.data
})
},
and use nuxt head (vue-meta)
head() {
return {
title:
this.$store.state.modules.general.info.name + ' / ' + this.Item.title,
meta: [
{
hid: 'description',
name: 'description',
content:
this.$store.state.modules.general.info.name +
' / ' +
this.Item.seo_description
},
}

Related

Nuxt: Dynamic og:image when generating static files

I am working on my first Nuxt project. I am trying to dynamically set the og:image URL by taking images of a post. In principle I am able to achieve this with the following code in the script
export default {
head() {
return {
title: this.post.title,
meta: [
{
hid: "description",
name: "description",
content: this.post.description,
},
{ hid: "og:title", property: "og:title", content: this.post.title },
{
hid: "og:description",
property: "og:description",
content: this.deck.description,
},
{ hid: "og:type", property: "og:type", content: "article" },
{
hid: "og:image",
property: "og:image",
content:
"https:[website]" +
require(`#/content${this.slug.dir}/images/preview.png`),
},
{
hid: "og:url",
property: "og:url",
content:
"https:[website]" + this.$route.fullPath,
},
],
};
},
async asyncData({ $content, params }) {
...
},
};
</script>
I notice the following:
On the browser page, when I open view source, these tags are not shown. However, the inspector shows the meta tags in the head .
This is as expected because, the view source is the base HTML head that is served from the backend, while the meta tags, the Nuxt JS must be dynamically adding on load.
I think we type the URL in a social media post like Facebook, WhatsApp, Twitter, LinkedIn, the manner it works is that only the head portion of the page is retrieved and the og parameters are retrieved to display the image. But the JS script is not executed.
And that is why I get a missing image error or a blank thumbnail.
The nuxt.config.js is as below
// nuxt.config.js
export default {
...
target: 'static',
...
ssr: false, // removing this makes no difference
...
}
Question is: how can I get Nuxt to add the meta tags in the generated HTML? Thanks

How to correctly put google sign-in code in a nuxt component

Google provides a friendly .html code in https://developers.google.com/identity/sign-in/web
I tried this code in a .html file and it works totally fine.
After the user is signed in, onSignin would be revoked every time the page is loaded, which means user info will be logged in console
But if I use this code in a nuxt component, only the sign-in process would be run, onSignIn function is not revoked, and no errors were shown.
Here's my code:
<template>
<div class="g-signin2" data-onsuccess="onSignIn"></div>
</template>
<script>
/* eslint-disable */
function onSignIn(googleUser) {
// Useful data for your client-side scripts:
var profile = googleUser.getBasicProfile()
console.log('ID: ' + profile.getId()) // Don't send this directly to your server!
console.log('Full Name: ' + profile.getName())
console.log('Given Name: ' + profile.getGivenName())
console.log('Family Name: ' + profile.getFamilyName())
console.log('Image URL: ' + profile.getImageUrl())
console.log('Email: ' + profile.getEmail())
// The ID token you need to pass to your backend:
var id_token = googleUser.getAuthResponse().id_token
console.log('ID Token: ' + id_token)
}
export default {
head() {
return {
meta: [
{
name: 'google-signin-scope',
content: 'profile email'
},
{
name: 'google-signin-client_id',
content: process.env.GOOGLE_CLIENT_ID
}
],
script: [
{
src: 'https://apis.google.com/js/platform.js',
defer: true,
async: true
}
]
}
}
}
</script>
I'm sure process.env.GOOGLE_CLIENT_ID is correct since I've checked dom tree when running on browser. If you know where the bug is please let me know, thank you.
Vue SFC's script is isolated, and you have declared onSignIn just in this scope. Yeah, this is not going to fly.
Luckily, you can simply add onSignIn function in window scope:
window.onSignIn = onSignIn
Mostly, you've got it all right. But there is even dedicated package ready for this use case: google-signin-vue. I would not recommend blindly using it though; instead look at source code and find features you'd like to have, if needed.
I solved this problem by myself. I checked: how to implement Google Login API in VueJS?
and use the second method the answer provided.
I moved properties in head() to nuxt.config.js like this:
// put this in script array
{
src: 'https://apis.google.com/js/platform.js?onload=renderButton',
defer: true,
async: true
}
// ...
// put this in meta array
{
name: 'google-signin-scope',
content: 'profile email'
},
{
name: 'google-signin-client_id',
content: process.env.GOOGLE_CLIENT_ID
}
in component
// template
<div id="google-signin-button"></div>
// methods
onSignIn(user) {
console.log('invoking onSignin...')
const profile = user.getBasicProfile()
console.log('ID: ' + profile.getId()) // Don't send this directly to your server!
console.log('Full Name: ' + profile.getName())
console.log('Given Name: ' + profile.getGivenName())
console.log('Family Name: ' + profile.getFamilyName())
console.log('Image URL: ' + profile.getImageUrl())
console.log('Email: ' + profile.getEmail())
// The ID token you need to pass to your backend:
var id_token = user.getAuthResponse().id_token
console.log('ID Token: ' + id_token)
}
// mounted lifecycle
mounted() {
setTimeout(() => {
gapi.signin2.render('google-signin-button', {
onsuccess: this.onSignIn
})
})
},
And it works finally. Hope this will help someone.

Is there a way i can get a route parameter in vue

I am new to vuejs, i have my api in laravel having a route such as
Route::get('/get-song-details/{id}','SongsController#getSongDetails');. How do get this id in vue so that i can display only information about the selected song.
in the sample below, when i pass 1, i get information about song 1, and so on. how do i make it dynamic?
export default {
data(){
return {
songs : []
}
},
created(){
axios.get('/api/get-song-details/1')
.then(response => this.songs = response.data);
}
};
</script>
asumming you are using vue-router, the route component should be declared so:
routes: [
{ path: '/song/:id', component: Song }
]
then in your created method of Song component can get the id param:
created() {
axios.get('/api/get-song-details/' + this.$route.params.id)
...
}
All route params can be accessed by using this.$route.params.paramName in JS code or by using $route.params.paramName in template. paramName is the parameter name as defined in your router.

How to initiate refresh of Vuejs page elements w/ new data?

I have a vuejs app using vue-router with the following routes.
const routes = [
{ path: '/list', component: list, alias: '/' },
{ path: '/resources/:id?', component: resources },
{ path: '/emails', component: emails },
{ path: '/list/:id', component: editHousehold, props: true },
{ path: '/list/turn-off/:id', component: editHousehold, props: true }
]
The first time the page loads the start event calls /resources w/o an ":id" and the page loads a list of resources (see below).
start: function () {
this.$http.get('/resources')
.then((res) => {
let gdriveInfo = res.data;
this.files = gdriveInfo.files;
}
);
},
Resource1
Resource2
Rescouce3
...
When the user clicks on one of the resources in the list I want to have /resources/1 called so a different set of resource data can be loaded and displayed.
I have a file click event attached to each resource where the "id" is appended to the path. This calls the server side module which would retrieve new data which would replace the "files" data in the component which I would expect would cause vuejs to "react" and update the contents of the page.
onFileClick: function (id, mimeType, event) {
const _this = this;
this.$http.get('/resources/' + id)
.then((res) => {
let gdriveInfo = res.data;
this.files = gdriveInfo.files;
}
);
}
However, calling above does not initiate a call to the server module.
this.$http.get('/resources/' + id)
I've also tried
this.$router.push('/resources/' + id)
which did not work.
Being new to vuejs, any help in how to achieve this functionality would be appreciated.
You lack host, because this.$http.get('/resources/' + id) is u component resources, this not json...
It looks like you're not making the REST call correctly. I think you're getting routing and REST calls mixed up. What you show above is for routing not making calls to the server.
You're not calling the server here:
this.$http.get('/resources/' + id)
and doing this is just for the routing:
this.$router.push('/resources/' + id)
Look at using axios for REST calls:
https://github.com/axios/axios

Dynamic build routes {or dynamic component import} Angular 2 [duplicate]

This question already has answers here:
Async load routes data and build route instruction for Angular 2
(4 answers)
Closed 6 years ago.
Maybe anyone know how to dynamicly build routes (or just dynamic import Components).
For example:
I have JSON that contains objects with RouteName, path, ComponentNames (string).
I want to iterate it and build dynamicly routes definitions (route config). But I don`t know, how to make dynamic Component import.
I can passs string "ComponentName" from JSON to import rule, because import want static definition (finded it on some soure from googling).
failed
let a = "MyComponentName"
import {a} from ......
(One idea that I came up with - its like create some map key-value, and keep into key - route, value - Component, and after that equals routename from JSON and my MAP and push needed component into final route config array. But its so ugly solution) Maybe another way exists?
I stuck. Many thanks for any help.....
You could leverage Async routes to do this. Based on your route configuration, you could load route from modules. In this case, you need to add the module path to get the components to associate with routes.
Here is a sample:
var routes = {
path: '/path',
name: 'some name',
module: './my.component',
component: 'MyComponentName'
}
routes.forEach((route : any) => {
this.routeConfigArray.push(
new AsyncRoute({
path : route.path,
loader : () => System.import(route.module).then(m => m[route.component]),
name : route.name
});
);
});
this._router.config(this.routeConfigArray);
Another approach could be to add a function to get the name of functions. Based on this you can check if you have a potential component that matches.
Here is a sample:
ngOnInit() {
this.routes = [
{
path: '/test', component: 'OtherComponent', name: 'Test'
}
];
this.configureRoutes(this.routes);
this.router.config( this.routes);
}
configureRoutes(routes) {
var potentialComponents = [ OtherComponent ];
routes.forEach((route) => {
route.component = potentialComponents.find((component) => {
return component.name === route.component;
});
});
}
See this plunkr: https://plnkr.co/edit/KKVagp?p=preview.
See this question for more details:
Dynamic Route Loading in Angular 2 Fails. (Beta)
https://github.com/angular/angular/issues/11437#issuecomment-245995186 provides an RC.6 Plunker
update
In the new router (>= RC.3) https://angular.io/docs/js/latest/api/router/index/Router-class.html#!#resetConfig-anchor resetConfig can be used
router.resetConfig([
{ path: 'team/:id', component: TeamCmp, children: [
{ path: 'simple', component: SimpleCmp },
{ path: 'user/:name', component: UserCmp }
] }
]);
original
What should work is
import from 'myComponents' as myComponents;
...
someFunc(name:string) {
console.debug(myComponents[name]);
}
Routes can be loaded using
constructor(private router:Router) { }
someFunc() {
this.router.config([
{ 'path': '/', 'component': IndexComp },
{ 'path': '/user/:id', 'component': UserComp },
]);
}
I haven't tried this myself.
See also this related question Angular2 App Routing through Services
say. three screens as page1, page2 and page3 and components as app/page1.ts, app/page2.ts and app/page3.ts
let screens : Array<string> = ["Page1","Page2","Page3"];
let aRouter : RouteDefinition;
this.routes = new Array<RouteDefinition>();
screens.map(function(screenId){
aRouter = new AsyncRoute({
path: "/" + screenId,
name: screenId,
loader: () => System.import("app/" + screenId).then(c => c[screenId]) // not import {page1, page2, page3}}
});
this.routes.push(aRouter);
}.bind(this)); //we need to bind to current "this" instead of global this
this.router.config(this.routes);
trick is .bind(this), which is vanella javscript
for whole sulution, check this
Dynamically load Angular 2 Async router
https://github.com/Longfld/DynamicalAsyncRouter