Using async data for seo head elements in nuxt3 - html

I am trying to create a site using data fetched from a directus instance.
Currently I have a layout component app.vue filling all seo meta tags using static default values hardcoded in that file.
So in the setup I am using:
useSeoMeta({
title: () => "Static title"
})
which is not creating the desired output. No title is rendered.
Also for a post component I want to overwrite the values from layout using data fetched from a remote source:
const { data: post, pending } = await useAsyncData('post', () => {
return getItemById({
collection: "collection_id",
filter: {
status: "published"
},
id: route.params.id,
}).then((data) => {
let ast = Markdoc.parse(data.content);
let transform = Markdoc.transform(ast);
data.content = Markdoc.renderers.html(transform);
useSeoMeta({
title: data.seo_title,
});
return data;
});
});
This is also not working as expected and serves different result, depending weather ssr is applied or not.
How would one implement a solution like this?

Related

I can't fill a request response using axios in state variable in React.js with Next.js

I'm working with React.js and I have the following problem:
import axios from "axios";
export default function Home() {
const [products, setProducts] = useState([]);
const ax = axios.create({ headers: { Accept: 'application/json' }});
function test() {
const res = ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search").then((response) => {
// expected the setProducts to be filled with the return of this request
setProducts(response.data);
});
}
test();
// and when I get here to see if the products have been filled, I get an empty array [ ]
console.log(products);
/*
as the products variable was not filled within the axios promise by setProducts,
there is no way to throw the products array here in the HTML to make a forEach or
a map to look cute together with the tags
*/
return (
<sup>how sad, with the product array empty, I can't put the data here '-'</sup>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
See how the result comes out in the IDE console:
I'm in Visual Studio not knowing what to do, I'm new to ReactJS with NextJS and from an early age I've been trying to see if I could solve this problem, but without success.
What can I do to bring the products to the HTML page?
UPDATE: As per the solution below, I created a possible workaround that indicates a path that could have returned a solution
ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search/", {})
.then((response) => setProducts(response.data))
.catch((error) => {
console.log(error); // AxiosError {message: 'Network Error', name: 'AxiosError', ...}
console.log(error.status); // undefined
console.log(error.code); // ERR_NETWORK
});
useEffect(() => {
console.log(products);
}, []);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.2/umd/react-dom.production.min.js"></script>
and I'm getting the same error that I put in the comments of the first answer below:
but when I change the setProducts by the console.log to see if it returns the same result, this appears in the terminal where my next.js application is running
that:
ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search/", {})
.then((response) => console.log(response.data.length)) // returns the length of the products array
returns this when I update my app:
NOTE: That's why I'm not able to understand my application in Next.js. I'm following all the correct guidelines, writing the code perfectly using axios and when I run the application on the website it gives a network error and doesn't show exactly the amount of products that were displayed in the terminal where my application is running.
I've already configured all the request headers correctly, enabling CORS to allow external requests with other API's, and I still don't succeed in returning the data to my application's page.
Wrap the stuff you have to fetch products inside useEffect hook
useEffect(()=>{
const ax = axios.create({ headers: { Accept: 'application/json' }});
function test() {
const res = ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search").then((response) => {
// expected the setProducts to be filled with the return of this request
setProducts(response.data);
console.log(response.data)
});
}
test();
},[])
Then in your return of the component, you can use map on products array with null and undefined checks
Like
{products && products.map(product=>{})}

How to identify different handlebar templates?

I have several html files in my project which are templates to email messages, like email verification, password reset, etc...
I need to precompile these files and use them in the right place, for example, the email verification template must be sent in the registration function. The problem is how do I identify the templates to use them, given that I don't know from which type they are? How can I create some kind of identifier for the templates?
You can save your compiled templates in some data structure, returning it somehow and using it afterward.
Here down a sample based on your processing function and using Map as the data store:
export function preCompileTemplates(globString: string) {
const paths = getPathsFromGlob(globString)
const preCompiledTemplatesPs = paths.map(path => {
const templateName = path.substring(path.lastIndexOf('/') + 1, path.length - 5);
return fs.promises.readFile(path).then(template => {
return {name: templateName, content: Handlebars.precompile(template)}
})
})
const templates = new Map()
return Promises.all(preCompiledTemplatesPs, (preCompiledTemplates) => {
preCompiledTemplates.forEach(template => {
templates.set(template.name, template.content)
})
return templates
})
}

Save specific Json from specifiq request link

I want to scrape specific JSON from specific request link "http://website.com/request/api" on page.
I have to scroll to the bottom of the page to get all the articles (already coded). At each scroll, I would like to get the JSON corresponding to the articles just displayed.
So there are 2 problems:
The fact that the same URL query "http://website.com/request/api" is also used to returns other JSON which is not useful for me (other elements of the page).
The fact of having several JSONs to collect and assemble
For problem 1, I thought of adding a condition to my code to get only the JSON beginning with a precise text "Data : object"?
For the problem 2, I should be able to write in a file or the buffer the different JSON selected by assembling them.
Do you know how I could do it?
page.on('response', async(response) => { const request => response.request();
if (request.url().includes('/api/graphql/')){
const text = await response.text();
fs.writeFile('./tmp/response.json', JSON.stringify((text)));
console.log(text);
}
})
i have resolve the problem.
listener = page.on('response', async response => {
const isXhr = ['xhr','fetch','json'].includes(response.request().resourceType())
try {
if (isXhr){
if (response.url().includes('/api/graphql/')) {
const resp = await response.buffer();
if (resp.includes('Data : object')) {
fs.writeFileSync('./tmp/response.json', resp, { flag: 'a+' })
}
}
}}
catch(e){}
})

React constant with parameters using square brackets

I'm new to React.
I have the code below with a function, but when I run it, it returns an error:
TypeError: renderJson[item.node] is not a function.
How can I fix the renderJson function?
export const readItem = item => {
printlog(item);
return renderJson[item.node](item);
};
const renderJson = {
"heading": item => <h1>{item.map(item => readItem(item))}</h1>
};
If you're trying to create a single React functional component that takes a JSON, and outputs the items in the JSON as a header, it would be more like this:
// If you're getting this JSON from an external source using something like a GET request, put the request inside a "useEffect()" hook
const myJson = {
"heading": ["My First Header", "My Second Header"]
};
export const Header = () => {
console.log(myJson);
return <h1>{myJson.heading.map(header => header}</h1>
};
I apologize if this is a misinterpretation of your question. If it is, any additional details would be helpful.

Populating a BackboneJS model with response from an API endpoint

I'm new to BackboneJS but I'm doing my best to learn it. I'm more familiar with AngularJS so I have some confusion in BackboneJS but would definitely want to become an expert BackboneJS developer too.
Back at my previous job, I was the frontend dev and I would work with the Java dev guy. We would have a meeting about how the JSON response would look like. Basically, I'll make a REST call(either with Restangular or $http) to one of their endpoints and I'll get a response. The JSON response will be assigned to a scope variable such as $scope.bookCollection. In my template, I'll just use ng-repeat to display it.
Now with BackboneJS, I'd like to do it properly. I read today that a BackboneJS Model is a container. What I'd like to happen is that after making a fetch(), I want the JSON response to be put in the Model that I defined. How is that done?
I found an example jsfiddle but I think it's a very bad example. I can't find something that is helpful right now, something with a good fetched data.
require.config({
paths: {
jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min',
underscore: 'http://underscorejs.org/underscore',
backbone: 'http://backbonejs.org/backbone-min'
},
shim: {
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
},
underscore: {
exports: "_"
}
}
});
require([
'jquery',
'underscore',
'backbone'], function ($, _, Backbone) {
var UserModel = Backbone.Model.extend({
urlRoot: '/echo/json/',
defaults: {
name: '',
email: ''
}
});
var userDetails = {
name: 'Nelio',
email: 'nelio#angelfire.com'
};
var user = new UserModel(userDetails);
user.fetch({
success: function (user) {
console.log(user.toJSON());
}
});
});
Here is the jsfiddle:
http://jsfiddle.net/20qbco46/
I want the JSON response to be put in the Model that I defined. How is
that done?
If you are trying to render the data from you model, you will use a view for this:
First, create a view to render your data:
// Create a new view class which will render you model
var BookView = Backbone.View.extend({
// Use underscores templating
template: _.template('<strong><%= title %></strong> - <%= author %>'),
initialize: function() {
// Render the view on initialization
this.render();
// Update the view when the model is changed
this.listenTo(this.model, "change", this.render);
},
render: function() {
// Render your model data using your template
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
See also: template and toJSON as well as $el
Next, create a Model:
// Create a model class
var Book = Backbone.Model.extend({
urlRoot: '/echo/json/',
defaults: {
title : '',
author: ''
},
});
Your model will hold the data fetched from the url / urlRoot
You can use set if you are trying to add new attributes to your model.
You can use get to grab attributes from your model.
See also - save and destroy.
Then, instantiate your model:
// Some dummy data
var instance = {
title: 'learn Backbone JS',
author: 'Bobby Longsocks',
};
// Instansite your model
var model = new Book(instance);
And finally, fetch your model data and create a new instance of you view:
// Fetch your model
model.fetch({
success: function(book) {
// Instansite your view, passing in your model
var view = new BookView({model: book, el: $('body')});
}
});
Here is an Example you can fiddle with.
And some further reading: Annotated Source