#frontmater data to script tag?
1 messages · Page 1 of 1 (latest)
To access the books constant defined in the frontmatter within your <script> tag, you can use the define:vars directive in Astro. This allows you to pass server-side variables from your component frontmatter into client-side scripts. Here's how you can modify your code to achieve this:
---
const { data } = Astro.props;
interface Book {
isbn: number;
title: string;
description: string;
image: string;
}
const books: Book[] = data;
import { Image } from "astro:assets";
---
<div class="grid grid-cols-4 gap-y-10">
{
books.map(({ isbn, title, description, image }) => (
<>
<div data-key={isbn}>
<button id="listing" data-title={title} data-description={description}>
<div class="p-4 flex justify-center items-center flex-col">
<Image
src={image}
alt="test"
width="250"
height="250"
class="rounded-2xl"
/>
<h2 class="mt-4">{title}</h2>
</div>
</button>
</div>
</>
))
}
</div>
<dialog id="dynamic-modal" class="modal">
<!-- ... (dialog content remains the same) ... -->
</dialog>
<script define:vars={{ books }}>
function openModal({
title,
description,
}: {
title: string;
description: string;
}) {
(document.getElementById("modal-title") as HTMLElement).textContent = title;
(document.getElementById("modal-desc") as HTMLElement).textContent = description;
(document.getElementById("dynamic-modal") as HTMLDialogElement).showModal();
}
document.addEventListener("DOMContentLoaded", () => {
const listings = document.querySelectorAll("#listing");
listings.forEach((listing) => {
listing.addEventListener("click", () => {
const title = (listing as HTMLElement).dataset.title || "";
const description = (listing as HTMLElement).dataset.description || "";
openModal({ title, description });
});
});
});
</script>
In this modified version:
1. We use the `define:vars` directive on the `<script>` tag to pass the `books` array from the frontmatter to the client-side script:
```astro
<script define:vars={{ books }}>
This makes the books array available within the script.
-
We add
data-titleanddata-descriptionattributes to each button in the template:<button id="listing" data-title={title} data-description={description}> -
In the script, we retrieve the title and description from the button's dataset when it's clicked:
const title = (listing as HTMLElement).dataset.title || ""; const description = (listing as HTMLElement).dataset.description || "";
This approach allows you to access the book data in your client-side script while maintaining the separation between server-side and client-side code.
Note that using define:vars implies the is:inline directive, which means your script won't be bundled and will be inlined directly into the HTML. For more information, you can refer to the Astro documentation on the define:vars directive.
Astro Documentation: define:vars directive
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@stable comet Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@somber cloud that means that i can no longer use my tyoe annotations in my script file isnce it is no longer typsecriupt?
Let me check the knowledge base for you again. One moment! :books:
You're right to be concerned about TypeScript support when using the define:vars directive, but I can reassure you that you can still use TypeScript in your script tag. Let me explain:
-
TypeScript in Astro scripts: Astro has built-in support for TypeScript, even in inline scripts. As mentioned in the Astro TypeScript documentation, you can write TypeScript code directly inside your Astro component script and any script tags.
-
define:varsand TypeScript: While usingdefine:varsdoes imply theis:inlinedirective, which means your script won't be bundled, it doesn't prevent you from using TypeScript. You can still use type annotations and other TypeScript features in your inline script.
Here's how you can modify your script to maintain TypeScript support:
<script define:vars={{ books }}>
interface Book {
isbn: number;
title: string;
description: string;
image: string;
}
function openModal({
title,
description,
}: {
title: string;
description: string;
}) {
(document.getElementById("modal-title") as HTMLElement).textContent = title;
(document.getElementById("modal-desc") as HTMLElement).textContent = description;
(document.getElementById("dynamic-modal") as HTMLDialogElement).showModal();
}
document.addEventListener("DOMContentLoaded", () => {
const listings = document.querySelectorAll("#listing");
listings.forEach((listing) => {
listing.addEventListener("click", () => {
const title = (listing as HTMLElement).dataset.title || "";
const description = (listing as HTMLElement).dataset.description || "";
openModal({ title, description });
});
});
});
</script>
In this example, you can see that we're still using TypeScript features like interface declarations and type annotations. Astro will process this TypeScript code correctly, even though it's in an inline script.
However, it's worth noting that while you can use TypeScript in inline scripts, you won't get the full benefits of separate compilation and type checking that you would with external TypeScript files. If you need more advanced TypeScript features or want to leverage separate compilation, you might consider moving your script to an external .ts file and importing it.