#Extract <p> tag from component jsx node
18 messages · Page 1 of 1 (latest)
I want to do this, because I need a short description about blog posts, therefore I extract the first <p> tag from these posts.
What do you mean with extract?
@hollow isle I need the first <p> tag’s content from a component. For example: <p> The following blog post is about … </p> I have to do this automatically. I want to create a snippet card for every blog post on my homepage. I store my blog posts under /routes/posts. So I’ll load all route under posts, then I need to make a short description about the posts. Thats why I need the first <p> tag.
did you try with ref? https://qwik.builder.io/docs/components/overview/#getting-hold-of-dom-element
you can get the dom element and query for the <p> tag
As I said It would be great, if I can do this automatically, without touch the blog page components.
Do you need the description to populate the page metadata?
I just want to create card like this automatically, without touch the blog posts.
So I have to load all blog post components, then I have to “extract” description info about the post.
The first paragraph is enough to me to display in the cards
Do you understand the problem now?
I see. do you have a public repo to play with it?
Currently I’m on phone, but I’ll make a repo! @hollow isle thanks the help, I’ll write if I’m at home.
If you create a repo we will find a smart solution
// Find the first <p> tag, throw error if contains anything else than plaintext
function extractSnippetFromJsxNode(jsxNode: JSXNode): string | undefined {
for (const node of jsxNode.children ?? []) {
if (node.type == "p") {
if (typeof node.children != "string") {
throw Error(
"INVALID FIRST PARAGRAPH OF BLOG POST," +
" BLOG POST FIRST <p> should only contain plain text"
);
}
return node.children;
}
}
}
export const usePostSummaryLoader = routeLoader$(async (requestEvent) => {
const modules = import.meta.glob(`/src/routes/posts/**/**/index.tsx`);
const postSummaries: BlogPostSummary[] = [];
for (const moduleName of Object.keys(modules)) {
const importedRoute = await modules[moduleName]();
const head: BlogPostHead = (importedRoute as any).head;
if (head == undefined) {
return requestEvent.fail(500, { errorMessage: "Missing post's head" });
}
const relativeUrl = moduleName
.replace("/src/routes", "")
.replace("/index.tsx", "");
const jsxNodeQRL: any = (importedRoute as any).default({}, null, 0);
const component = await jsxNodeQRL.props["q:renderFn"]();
const summary: BlogPostSummary = {
title: head.title!,
headerImageUrl: head.headerImageUrl,
introductionTextHTML: extractSnippetFromJsxNode(component) ?? "",
relativePostUrl: relativeUrl,
releaseTimestamp: head.releaseTimestamp,
tags: head.tags,
};
if(summary.introductionTextHTML == ""){
return requestEvent.fail(500, { errorMessage: `Missing introduction text of ${summary.title}` });
}
postSummaries.push(summary);
}
return {
errorMessage: undefined,
postSummaries: postSummaries,
};
});
Btw, this is my current solution. Because the components are lazy-loaded (QRL), we have to resolve these first.
It looks dirty:
const jsxNodeQRL: any = (importedRoute as any).default({}, null, 0);
const component = await jsxNodeQRL.props["q:renderFn"]();