#My markdown frontmatter props are always undefined

35 messages Β· Page 1 of 1 (latest)

obtuse robin
#

Hi! I'm stuck with Astro on markdown files. I'm trying to put the MD title in the component, but it's always failing and its stating that title (or any other term i put in) is undefined on dev.

Here's my MD:

---
layout: ../../components/Stickie.astro
title: First
--- 

### First title
This is the description of the first one.

And my component:

---
const {frontmatter} = Astro.props;
---

<h3>{frontmatter.title}</h3>
<slot />

And my component is on src/components and my MDs are in src/content/stickies/
Shouldn't this work simply like this? Or what am I missing from the docs? Thank you

boreal krakenBOT
#
Quiet in here?

It looks like no-one has responded to your question yet. People might not be available right now or don’t know how to answer your question. Want an answer while you wait? Try asking our experimental bot in #1095492539085230272.

lean acorn
#

I'd like to know how you ended up rendering this page, if I'm right you should have imported and used the Stickie.astro component directly in other pages, instead of trying to use content collections. If you just want to simply render markdown, there are two ways to modify it:

  1. Put the markdown in the src/pages directory and don't use <Stickie /> in other pages, Astro's file system-based routing will automatically add this file, at this point Stickie.astro just serves as a template to provide a shell for the markdown page.

  2. If you want to make a component that loads markdown content and then use it in other pages, please refer to importing-markdown.

Note: content collections is an Astro feature, if you don't plan to use it, please don't put your markdown files in the src/content directory.

If you have any new questions, please feel free to ask!

Astro Documentation

Content collections help organize your Markdown and type-check your frontmatter with schemas.

Astro Documentation

Learn how to create content using Markdown or MDX with Astro

obtuse robin
#

ah, yes! To put it simply, i'm trying to render a whiteboard. So it's a one-page layout, which will be my index.astro. Then i have this reusable component called Stickie, which is a post-it. Now i want to be able to use the MDs as content for all my stickies. So it's a DB of MDs.

Thanks for the help!

I'm investigating the importing MDs, but without success (yet). So, i should be able to grab my stickies like this const stickies = await Astro.glob('../content/stickies/*.md'); but i still can't get the MD title... I need to investigate how do i get to choose which MD i want from index.astro in a structure like this stickie.md>stickie.astro>index.astro

obtuse robin
#

I managed to get the MD inside the index.astro

---
import Layout from '../layouts/Layout.astro';
import Stickie from '../components/Stickie.astro';
const allStickies = await Astro.glob("../content/stickies/*.md");
---
<div>{allStickies.map((post) => <Stickie {post} >Default content</Stickie>)}</div>

And then in stickie.astro i get it like this

---
const {post} = Astro.props;
---
<div>
    <h3>{post.frontmatter.title}</h3>
    <slot />
</div>

So, it's working and it's lean. But i don't understand how i can get the MD content into the <slot />...

It doesn't seem to work either if i try it like this {post.Content}. I don't really understand how to grab the markdown in Astro. It must be something obvious and simple because i'm almost there

knotty bison
#

I suggest using Content Collections instead of Astro.glob(), you can do something like this:

---
import { getCollection } from 'astro:content';
import Layout from '../layouts/Layout.astro';
import Stickie from '../components/Stickie.astro';
const allStickies = await getCollection('stickies');
---
<div>
  { allStickies.map((post) => {
    const { Content } = await post.render();
    return (
      <Stickie {post} >
        <Content />
      </Stickie>
    )
   })}
</div>

This page in the docs goes over how to setup Content Collections https://docs.astro.build/en/guides/content-collections

pearl nova
#

Yeah, and then I was going to post the content collections which Bryce just did πŸ˜‚

#

Btw what I posted is just the example at that link, not the code you'll use (tweak it to your case obviously)

#

Bottom line is you access the content through the Content component, hence the <Content /> syntax, because it's a component reference.

obtuse robin
#

Thank you, everyone! It was very helpful.

Following on this, i stumbled into another problem, that actually i should've noticed it before, because the problem was already there. I'm getting the "#" before the headings of markdown...

So, my markdown is not rendering as HTML. The content is just there dumped as a string. There are no errors on sight. Any ideas on where i should start looking?

Here's how i'm getting the content in the .astro

---
import {getCollection} from "astro:content";
const allStickies = await getCollection("stickies");
---
<div>
    {
        allStickies.map(post => (
            <h3>{post.data.title}</h3>
            <div>{post.body}</div>
        ))
    }
</div>

I'm also backed up by this tutorial: https://www.youtube.com/watch?v=zUmqmuSvJMs

In this video, I’ll take you through the process of updating our blog to the new Content Collections API for a type-safe markdown experience with error-checking that actually helps!

(FWIW, this video is NOT sponsored by Astro)

πŸ‘¨β€πŸš€ Astro Course Links πŸ‘¨β€πŸš€

β–Ά Play video
knotty bison
obtuse robin
#

hey @knotty bison thanks again!

I'm using your example but i'm getting the "await can only be used inside an async function". This is a bit out of my league here. Trying to search around how to solve this... Do you know how to?

lean acorn
#

@obtuse robin Attention should be paid to the rendering timing of post, which should be done in Stickie.astro

#

At this point your Stickie.astro should look like this:

---
const {post} = Astro.props;
const { Content } = await post.render();
---
<div>
    <h1>{post.data.title}</h1>
    <Content/>
</div>
#

and used in the page like this:

---
import { getCollection } from 'astro:content';
import Stickie from '../components/Stickie.astro';
const allStickies = await getCollection('stickies');
---
<div>
    { allStickies.map((post) => {
        return (
                <Stickie post={post} />
        )
    })}
</div>
obtuse robin
#

Thank @lean acorn ! I adapted it again to go in the Stickie.astro

Now it's returning the error "Cannot read properties of undefined (reading 'render')". Should i define something inside the render()?

#

I don't understand because the render function is in fact inside post πŸ€”

lean acorn
#

The render() function doesn't need to be changed because it's an Astro built-in function and you need to check that the post is passed correctly, This problem occurs because the post gets a null value.

obtuse robin
#

Hum... So i cannot get post because this piece is causing the error on index.astro:

{ allStickies.map((post) => {
    return (
        <Stickie post={post} />
    )
})}

Not sure how to solve this one... Even ChatGPT outputs the code exactly as you shared with me... How did i mess up the post and how can i troubleshoot that?

#

Can this say more about it?

TypeError: Cannot read properties of undefined (reading 'render')
at eval (/src/components/Stickie.astro:11:34)
at Stickie (/node_modules/astro/dist/runtime/server/astro-component.js:22:12)
at Module.renderToString (/node_modules/astro/dist/runtime/server/render/astro/factory.js:13:31)
at renderJSXVNode (/node_modules/astro/dist/runtime/server/jsx.js:77:87)
at renderJSXVNode (/node_modules/astro/dist/runtime/server/jsx.js:116:36)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

obtuse robin
#

Does having the code bit above clash with the fact that the component structure is Stickie.astro > Layout.astro > index.astro? Do i need to declare something inside Layout.astro?

#

...But i don't think so otherwise, i wouldn't receive the same error when bundling everything in the index.astro

lean acorn
#

Did you use the Layout template in Stickie.astro? By the way, please check where markdown is located, it's likely that allStickies didn't receive the right object in the first place. If you don't mind, you can share your project directory structure.

obtuse robin
#

Here's the file structure in the image.

Do i need to use Layout in Stickie? So i have the Stickie:

---
const {post} = Astro.props;
const {Content} = await post.render();
console.log(Content);
---
<div>
    <h1>{post.data.title}</h1>
    <Content/>
</div>

Then i have the Layout:

---
export interface Props {
    title: string;
}
const {title} = Astro.props;
---
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
        <meta name="generator" content={Astro.generator} />
        <title>{title}</title>
    </head>
    <body>
        <slot />
    </body>
</html>

And i combine both in the index.astro:

---
import Layout from "../layouts/Layout.astro";
import Stickie from "../components/Stickie.astro";
import {getCollection} from "astro:content";
const allStickies = await getCollection("stickies");
---
---
import Layout from "../layouts/Layout.astro";
import Stickie from "../components/Stickie.astro";
import {getCollection} from "astro:content";
const allStickies = await getCollection("stickies");
---
<Layout title="Portfolio">
    <main id="whiteboard">
        <section id="home">
            <h1>Portfolio</h1>
            <div>
                { allStickies.map((post) => {
                    return (
                        <Stickie post={post} />
                    )
                })}
            </div>
        </section>
        <section id="about">
            <h2>About</h2>
        </section>
        <section id="why">
            <h2>Why</h2>
        </section>
        <section id="see">
            <h2>See</h2>
        </section>
    </main>
</Layout>

I did bundled everything in index.astro and the error returns the same

#

I don't understand why i get duplicated markdown props from allStickies

#

nevermind, had another console.log elsewhere. This is the allStickies

lean acorn
#

I'm really puzzled, it doesn't look like there is any problem with the data in allstickies, I reproduced it according to your project structure and there is nothing wrong with it, did you do some server-side rendering related configuration? Or is there something extra configured in that content/config.ts? That's the only difference between my project structure and yours.

obtuse robin
#

I have this in my config:

import { z, defineCollection } from "astro:content";

const stickies = defineCollection({
    schema: z.object({
        title: z.string(),
    }),
});

export const collections = {stickies};

I don't remember doing anything to any other file. I'm a bit dumb with programming so i avoid it as much as i can to not mess it up. I just stick to markup languages

#

Well... it looks a bit like a dead end... I'm going to start fresh maybe... If it fails i think i'm gonna give up on Astro πŸ˜“

#

thanks, @lean acorn !

obtuse robin
#

It's failing on a clean install... This structure is not working for some reason 😦

#

Not due to strange mess up of other core files

#

I don't get it... I see everything in the console.log

lean acorn
#

Sorry to hear that, you can try restarting a new project and adding these codes to try it out.