nuxt.js get default head in vue.js component - javascript

I am trying to get the head object that is configured by nuxt.config.js in a vue layout. In order to show the same title in an app bar as the page title.
I know that you can alter the page title with the head function in a vue component. But is it also possible to retrieve this information somehow?
<script>
export default {
data () {
return {
title: head.titleTemplate // possible?
}
},
head () {
// here it is possible to change it but how about getting it?
}
}
</script>
Another approach could be to get some data out of an page in the nuxt.config.js. But I think this is not how the hierarchy is structured.
Thanks for you help I am just starting to use javascript to code a website :)

(If I understand you correctly) You can use the changed callback to keep track of the latest meta info used (and thus the title).
Example:
head() {
return {
changed: (info) => {
this.title = info.title;
console.log(info, info.title);
},
};
},
data() {
return {
title: '',
};
},

In nuxt.config.js before export I have setted variable with a string of the title.
Then added it to the head section and create a new env section:
https://nuxtjs.org/api/configuration-env/
const title = `Site title`
export default {
head: {
title
},
env: {
title
}
}
This how I'm getting the title in any Vue component:
export default {
computed: {
title () {
return process.env.title
}
},
}
This helps you to keep your original title in process.env.title, even if you will want to change head.title dynamically.
Did anyone found a better solution maybe? :)

Related

Wait for data in mapstate to finish loading

I have stored a userProfile in Vuex to be able to access it in my whole project. But if I want to use it in the created() hook, the profile is not loaded yet. The object exists, but has no data stored in it. At least at the initial load of the page. If I access it later (eg by clicking on a button) everything works perfectly.
Is there a way to wait for the data to be finished loading?
Here is how userProfile is set in Vuex:
mutations: {
setUserProfile(state, val){
state.userProfile = val
}
},
actions: {
async fetchUserProfile({ commit }, user) {
// fetch user profile
const userProfile = await fb.teachersCollection.doc(user.uid).get()
// set user profile in state
commit('setUserProfile', userProfile.data())
},
}
Here is the code where I want to acess it:
<template>
<div>
<h1>Test</h1>
{{userProfile.firstname}}
{{institute}}
</div>
</template>
<script>
import {mapState} from 'vuex';
export default {
data() {
return {
institute: "",
}
},
computed: {
...mapState(['userProfile']),
},
created(){
this.getInstitute();
},
methods: {
async getInstitute() {
console.log(this.userProfile); //is here still empty at initial page load
const institueDoc = await this.userProfile.institute.get();
if (institueDoc.exists) {
this.institute = institueDoc.name;
} else {
console.log('dosnt exists')
}
}
}
}
</script>
Through logging in the console, I found out that the problem is the order in which the code is run. First, the method getInstitute is run, then the action and then the mutation.
I have tried to add a loaded parameter and played arround with await to fix this issue, but nothing has worked.
Even if you make created or mounted async, they won't delay your component from rendering. They will only delay the execution of the code placed after await.
If you don't want to render a portion (or all) of your template until userProfile has an id (or any other property your users have), simply use v-if
<template v-if="userProfile.id">
<!-- your normal html here... -->
</template>
<template v-else>
loading user profile...
</template>
To execute code when userProfile changes, you could place a watcher on one of its inner properties. In your case, this should work:
export default {
data: () => ({
institute: ''
}),
computed: {
...mapState(['userProfile']),
},
watch: {
'userProfile.institute': {
async handler(institute) {
if (institute) {
const { name } = await institute.get();
if (name) {
this.institute = name;
}
}
},
immediate: true
}
}
}
Side note: Vue 3 comes with a built-in solution for this pattern, called Suspense. Unfortunately, it's only mentioned in a few places, it's not (yet) properly documented and there's a sign on it the API is likely to change.
But it's quite awesome, as the rendering condition can be completely decoupled from parent. It can be contained in the suspensible child. The only thing the child declares is: "I'm currently loading" or "I'm done loading". When all suspensibles are ready, the template default is rendered.
Also, if the children are dynamically generated and new ones are pushed, the parent suspense switches back to fallback (loading) template until the newly added children are loaded. This is done out of the box, all you need to do is declare mounted async in children.
In short, what you were expecting from Vue 2.

SvelteKit: how do I do slug-based dynamic routing?

I am a newbie on Svelte and in coding in general. I'd prefer to learn SvelteKit (Svelte#Next) rather than sapper since that seems to be where Svelte is heading.
For my personal project, I need to support dynamic routing based on url slugs. How do I do that in SvelteKit? For example, if I have /blog directory and need to pull content based on its "id", how would I do that?
The part that I am having difficulty with is accessing the URL slug parameter.
Thanks in advance.
you can create a file with the [brackets] : touch src/routes/blog/[slug].svelte
And paste the following code
<script>
import { page } from '$app/stores';
</script>
{$page.params.slug}
Then navigate to your app http://localhost:3000/blog/123
You should see your result
In order to create content for the http://localhost:3000/blog page, you can modify src/routes/blog/index.svelte
As of SvelteKit 1.0 the path should be a directory in brackets, e.g. for /blog/<slug> you will add the following:
src/routes/blog/[slug]
|_ +page.js
|_ +page.svelte
Then in src/routes/blog/[slug]/+page.js you can add something like
export const load = ({ params }) => {
return {
slug: params.slug
}
}
which will return it as a data property to +page.svelte, so you can write something like:
<script>
export let data;
</script>
<h1>{data.slug}</h1>
Reference: https://kit.svelte.dev/docs/routing
Caveat - the info in my reply probably may not be valid as SvelteKit matures, but from experiments I have done thus far, this works:
Parameter based routing is similar to the sveltejs/sapper-template. You should learn how Sapper does it first. Lets say I have a route blog with a single param slug (/blog/page-1 & /blog/page-2)
Create a route component in routes/blog named [slug].svelte
Copy the content from the sveltejs/sapper-template example.
Rename the preload function to load with a single parameter such as ctx
Alter the return object to append your slug property to props
export async function load(ctx) {
let slug = ctx.page.params.slug
return { props: { slug }}
}
If your blog has multiple params for the slug (/blog/2021/01/29/this-is-a-slug), you can remove [slug].svelte and create a file name [...data].svelte and change your load method to:
export async function load(ctx) {
let [year, month, day, slug] = ctx.page.params.data;
return { props: { data: { year, month, day, slug }}}
}
Don't forget to define your data property as an object. Here's a typescript example:
<script lang="ts">
export let data: { slug: string, year: number, month: number, day: number };
</script>
From there use the values as {data.slug}, etc
Happy hacking
I also had some issues with the Typescript import so here is a complete Typescript example.
Structure:
src/routes/coins/[coin_name]
|_ +page.ts
|_ +page.svelte
+page.ts:
import type { PageLoad } from './$types';
export const load: PageLoad = ({ params }) => {
return {
name: params.coin_name
}
}
export interface CoinPage{
name: string
}
+page.svelte and the use of the data:
<script lang="ts">
import type { CoinPage } from "./+page";
export let data:CoinPage;
</script>
<h1>{data.name}</h1>

Title not changing | Angular 4

I'm trying to override the document title on a route.
This is the route with a default title.
{
path: 'artikel/:id/:slug',
component: ArticleComponent,
data: {title: 'Article', routeType: RouteType.ARTICLE,
description: metaDescription},
resolve: {error: ErrorResolverService, article: ArticleResolveService},
}
I am using an ArticleResolverService to get the article from the ID and then apply a new Title.
resolve(route: ActivatedRouteSnapshot): Observable<Article> {
let id = route.paramMap.get('id');
return this.as.getArticle(id).take(1).map(article => {
if (article) {
//this seems to set the title temporarely (flickering visible)
this.ts.setTitle(article.title);
return article;
}
return null;
});
}
Since this approach doesn't quite work I tried setting the title in the ArticleComponent, which is the target of the route. (This happens in ngOnInit)
this.route.data.subscribe((data:{article: Article}) => {
this.article = data.article;
//this seems to set the title temporarely (flickering visible)
this.ts.setTitle(this.article.title);
//using this in browser console works permanently
window['setTitle'] = (t) => this.ts.setTitle(t);
});
Whatever I am doing, everytime I load the page i see the flickering of the wanted title but then it gets instantly reset to the default title (if I don't use a default title it will just show the page URL in the title bar, also just after flickering of the wanted title).
How do i effectively set a permanent title for this page?
The last step from your question is not required (window['setTitle']). Works just fine with the approach below. The default title will show until the setTitle function is called, then it will stay at the new title
Import Title service
import { Title } from '#angular/platform-browser';
Inject it
constructor(
...
private titleService: Title,
) {...}
Use it in the ngOnInit
this.titleService.setTitle("Some custom title" + this.newInfoFromAPI);

vue-dplayer does not load video after passing the url in the options

I tried to get vue-dplayer working, but after using the official configuration the video does not load or play. When I inspect the code that is generated, I see the url on the page.
<template>
<div>
<d-player #play="play" :options="video" ref="player"></d-player>
</div>
</template>
<script>
import VueDPlayer from 'vue-dplayer'
import 'vue-dplayer/dist/vue-dplayer.css'
export default {
name: 'play',
components: {
'd-player':VueDPlayer
},
data () {
return {
video:{
url: 'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4',
pic: '../img/icons/01.jpg'
}
}
},
methods:{
play(){
console.log('play callback')
}
},
mounted(){
const player = this.$refs.player.dp
}
}
</script>
The problem is simply that you are not using an options object with the right keys. You are required to have an options object with a video key in it, but instead you are passing an object with the url and pic key. Simply wrap it in an extra object so it can find the options.
data () {
return {
options {
video:{
url: 'http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4',
pic: '../img/icons/01.jpg'
}
}
}
}
<d-player #play="play" :options="options" ref="player"></d-player>

Vue.js import images

So I am making an app with a control panel and i want to be able to change a few images inside the app dynamically and my problem is, it just won't work
This is the div I am trying to change
<div class="bg-image bg-parallax overlay" :style="`background-image:url(${bg1url})`"></div>
this is the script part of the Home.vue file
<script>
import axios from 'axios';
export default {
name: 'Home', // this is the name of the component
data () {
return{
page_data: {},
bg1url: null,
};
},
created() {
axios.get("http://localhost:5001/api/v1/pages")
.then((result) => {this.page_data = result.data.page_data});
this.bg1url = require('#/assets/img/' + this.page_data.background1);
alert(page_data.background1);
},
};
</script>
I have tried most of the suggestions on stack overflow but nothing seems to work.
I use the default webpack configurations and generated structure
Note: the parts with axios fetching from the backend work correctly. The only problem is adding the image to the style.
I think could be because you are setting the value for bg1url outsite of promise (calback function of axios), and so this make the code sync and not async
so please try to update, use this instead
created() {
axios.get("http://localhost:5001/api/v1/pages").then(result => {
this.page_data = result.data.page_data
this.bg1url = require('#/assets/img/' + this.page_data.background1);
});
},

Categories

Resources