I'm currently learning Svelte and I would like to parse an atom feed and render it on the screen, but I'm not sure how to start getting the feed in. Can someone point me in the right direction on how to do this with Svelte?
This is pretty unrelated to Svelte, the main two things are:
Getting the feed content
Parsing the feed content
Once you have an object representation of the feed it can be rendered using Svelte like any other object.
If you want to do this fully client-side, including getting the feed-content, e.g. via fetch, you will probably run into cross-origin issues, depending on where the feed is from. So you might have to fetch the feed on the server and pass it to the client.
To parse the feed you can e.g. use the DOMParser:
const feedDocument = new DOMParser().parseFromString(atomXmlText, 'text/xml')
The resulting object is a DOM document that can be traversed or queried like an HTML document.
Basic example:
<script>
let items = [];
async function load() {
const res = await fetch('...');
const text = await res.text();
const feedDocument = new DOMParser().parseFromString(text, 'text/xml')
items = [...feedDocument.querySelectorAll('entry')].map(item => {
const title = item.querySelector('title').textContent;
const url = item.querySelector('link').attributes['href'].value;
return { title, url };
});
}
load()
</script>
<ul>
{#each items as { title, url }}
<li>
<a href={url} target="_blank" rel="noreferrer noopener">
{title}
</a>
</li>
{/each}
</ul>
REPL
(I could not find a proper feed with the correct CORS headers to allow a fetch, so the REPL does not actually fetch() anything.)
RSS example for NY Times (May break at any point)
Related
I am making a blog using markdown.
From next.js.
After reading markdown using fs, the process of converting it to html is as follows.
const markdownToHtml = async (markdownValue: string) => {
const processedValue = await unified()
.use(remarkParse)
.use(remarkHtml)
.process(markdownValue)
const stringedValue = processedValue.toString()
return stringedValue
}
This allowed me to express markdown as my blog post.
However, I would like to provide several posts and 'previews' on other pages.
Like this page.
enter image description here
In order to do that, I want to print only the p-tag.
<h2>sorry..</h2>
<p>Hi!</p>
<p><img src="/assets/cardTmp.jpg" alt="tmp"></p>
<p>hello world</p>
<p><strong>bye</strong></p>
All I need is 'Hi! hello world bye'.
Should I use a regular expression or javascript function?
Do you have any recommended methods or libraries?
I tried to use a regular expression, but I'm sure there's a cleaner and clearer way.
You can do that :
// Parse the HTML string into a DOM tree
const doc = new DOMParser().parseFromString(html, 'text/html');
// Get all the <p> tags from the document
const presult = doc.getElementsByTagName('p');
// Loop through the <p> tags
for (let i = 0; i < presult .length; i++) {
console.log(presult[i].textContent);
}
I'm trying to replicate the nuxt 3 useFetch sample but no luck so far.
https://v3.nuxtjs.org/getting-started/data-fetching#usefetch
My post.vue page contains the below code:
<template>
<section>
<div v-for="mountain in mountains" :key="mountain">{{mountain}}</div>
</section>
</template>
<script setup>
const runtimeConfig = useRuntimeConfig()
const { data: mountains, pending, error, refresh } = await useFetch('/mountains',{
baseURL: runtimeConfig.public.apiBase,
pick: ['title']
})
console.log(mountains.value)
</script>
For some reason the data is not shown in template.
The console.log() shows Proxy {title: undefined}
I've realized that removing the pick option solves the issue, so I'm wondering if pick only works for objects and can't be used in arrays.
It's odd because the sample is using an array https://v3.nuxtjs.org/api/composables/use-fetch.
The pick option currently works only if you are fetching one document (one Js object).
In the official docs you can see they are fetching a specific document in their API: https://nuxt.com/docs/getting-started/data-fetching.
One option you have is to make an API route that returns one object only.
Inside of your <div>, you are trying to return {{mountain}}, but at the time this page loads there is no such variable--because the const mountains hasn't been fetched yet. What you need to do is add a <div v-if="mountains" v-for="mountain in mountains" :key="mountain">{{mountain}}</div>
For the brief moment it takes before the useFetch function to return mountains,the <div> will not try to show {{mountains}}, because the v-if prevents the <div> from being shown in the first place.
I've had a few errors trying to render single blog posts.
I tried using the page template with /post/{post_name} and I was getting this error:
warn Non-deterministic routing danger: Attempting to create page: "/blog/", but
page "/blog" already exists
This could lead to non-deterministic routing behavior
I tried again with /blog/{post_name}.
I now have both routes, which I'm not sure how to clean up; but more importantly, on those pages, nothing renders, even though there should be an h1 with it's innerhtml set to the node.title and likewise a div for the content.
I've uploaded my config and components to https://github.com/zackrosegithub/gatsby so you can have a look.
Not sure how to fix
I just want to see my content rendered on the screen.
Developer tools don't seem to help when there's no content rendered as I can't find anything to inspect to try to access it another way.
Thank you for your help
Your approach is partially correct. You are using a promise-based approach but when using then() you are already settling and partially resolving it so you don't need to use the callback of resolve(), which may be causing a duplication of the promise function so try removing it.
Additionally, you may want to use a more friendly approach using async/await functions. Something like:
exports.createPages = async ({ graphql, actions, reporter }) => {
const yourQuery= await graphql(
`
{
allWordpressPost {
edges{
node{
id
title
slug
excerpt
content
}
}
}
}
`
if (yourQuery.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`);
return;
}
const postTemplate = path.resolve("./src/templates/post.js")
_.each(yourQuery.data.allWordpressPost.edges, edge => {
createPage({
path: `/post/${edge.node.slug}/`,
component: slash(postTemplate),
context: edge.node,
})
})
})
// and so on for the rest of the queries
};
In addition, place a console.log(pageContext) in your postTemplate to get what's reaching that point and name the template as:
const Post = ({pageContext}) => {
console.log("your pageContext is", pageContext);
return <div>
<h1>
{pageContext.title}
</h1>
</div>
}
export default Post;
I setup and account at http://feedthefire.in and on Firebase dot com - to manage feeds I would liek to display on my site. I set everything up and the feeds get pulled into Firebase just like it should, now its time to add it to a web page...nothing, can't get the feeds to pull in from Firebase. I added the firebase.js reference in the header and in the body I placed
<script type="text/javascript">
var ref = new Firebase"'https://aodf.firebaseio.com");
ref.child("meta").once("value", function(snapshot) {
$("#e-title").html(snapshot.val().description);
});
ref.child("articles").limit(3).on("child_added", function(snapshot) {
var article = snapshot.val();
var link = $("<a>", {
"href": article.link,
"target": "_blank"
});
$("#e-list").append($("<li>").append(link.html(article.title)));
});
when you go to http://sandbox.studiorooster.com/ao I should see a list of feeds, but I don't, so I know I am supposed to place something else in the code; I think :)
There are a number of problems in what you posted above, each of which is explained below:
Syntax error on line #2: var ref = new Firebase("https://aodf.firebaseio.com");
You're loading a description on lines #3-5, but never rendering it, because there is no element with id e-title in the page you linked to. Trying adding <h2 id="e-title"></h2> to your template.
Similarly, you are loading a number of articles on lines #6-13, and trying to append each of these items to a list with id e-list, which also does not exist in your template. Try adding <ul id="e-list"></ul> to your template.
Hope that helps!
I am struggling to figure out the basic pattern for populating a template with data from a call to an external API in Meteor.
These are the elements in play
A fresh Meteor project, created by running meteor create monkeyproject
The URL of an external API that returns a JSON array. Let's say it's example.com/api/getmonkeys. It returns an array of monkeys, each with a different name.
A Handlebar template called monkeyTemplate with an {{#each}} loop. Let's say it's this:
<template name="monkeyTemplate">
{{# each monkeys}}
One of our monkeys is named {{name}}. <br>
{{/each}}
<input type="button" id="reload" value="Reload monkeys" />
</template>
What I want to happen
When the page loads fill monkeyTemplate with monkeys from our external URL.
When the user clicks the button, call the external URL again to reload the monkeys.
The question
What is a standard pattern for doing the above in Meteor? At the risk of cluttering up the question, I'll include some starting points, as I understand them.
We can populate the template with whatever we return from our Template.monkeyTemplate.monkeys function. How do we fill it with content from an external URL, given that the page will load before the external request is finished?
We can get our JSON by using Meteor.HTTP.call("GET", "http://example.com/api/getmonkeys", callback ). Where do we put this request, and what do we put into our callback function in this situation?
We can control what happens on the server side and what happens on the client side by using the Meteor.isServer/Meteor.isClient conditions, or by putting our code into files called client and server folders. What code needs to be on the server side vs. the client side?
We determine what happens when the button is clicked by attaching a function to Template.monkeyTemplate.events['click #reload']. What goes into our callback function in this situation?
I will refrain from cluttering up the question with my crappy code. I am not looking for anyone to write or rewrite an application for me—I am just looking for the guidelines, standard patterns, best practices, and gotchas. Hopefully this will be instructive to other beginners as well.
I'm not sure if this is the "standard" template, but it serves the purpose pretty well.
Set up two data helpers for the template, monkeys and loading. First one will display the actual data once it's fetched, the latter will be responsible for notifying user that the data is not yet fetched.
Set up a dependency for these helpers.
In created function of the template, set loading helper to true and fetch the data with HTTP call.
In the callback, set the template data and fire the dependency.
html
<template name="monkeys">
{{#if loading}}
<div>Loading...</div>
{{/if}}
{{#if error}}
<div>Error!</div>
{{/if}}
{{#each monkeys}}
<div>{{name}}</div>
{{/each}}
<div><button class="monkeys-reloadMonkeys">Reload</button></div>
</template>
js
var array = null;
var dep = new Deps.Dependency();
Template.monkeys.created = function() {
reloadMonkeys();
};
Template.monkeys.events({
'click .monkeys-reloadButton': function(e,t) {
reloadMonkeys();
};
});
var reloadMonkeys = function() {
array = null;
dep.changed();
HTTP.get('http://example.com/api/getmonkeys', function(error, result) {
if(!error && result) {
array = result;
} else {
array = 0;
}
dep.changed();
});
};
Template.monkeys.monkeys = function() {
dep.depend();
return array ? array : [];
};
Template.monkeys.loading = function() {
dep.depend();
return array === null;
};
Template.monkeys.error = function() {
dep.depend();
return array === 0;
};