how to refresh page when hitting api endpoint (nuxt.js) - node.js

I'm making an app that displays a list of orders. The problem is when I submit a new order by hitting an endpoint with a post request with the data for a new order, the page or the components need to refresh automatically to display this new order. I don't know how this is achieved with nuxt. The client-side HTML rendering needs to be actively reacting to events happening on the server-side.

So, you don't actually need to refresh the page to do this, you can use axios to POST an order and update your page with that particular order
export default {
data(){
return {
newOrder: null
}
},
methods:{
newOrder(){
const newOrder = await this.$axios.post(...)
this.newOrder = newOrder
},
}
}

Related

How to reflect changes in client when database changes?

So here's my scenario: I have a client page, where any one can fill and submit a form. the form data is stored in a database. There is a separate admin pc which is on an admin page, where every new form entry is displayed. How to update the front end of the admin everytime a new form is submitted, without refreshing/re hitting the API?
I am using React with express and MongoDB.
You can use TanStack Query (also called react query) ,
it's useQuery (a data fetching method) has a build-in property called isFetching which allow automatic fetching in a specific interval you want, like :
const { data,isLoading,isFetching } = useQuery(
['random-data'],
async () => {
const { data } = await axios.get(
'https://random-data-api.com/api/v1/random_data'
);
return data;
},
{
// refetch data every sec.
refetchInterval: 1000,
}
);
you can check more here

Is it possible to have protected routes in Remix.run, so the browser doesn't get the protected source code?

Is it possible to have protected routes in the Remix.run React framework, so that only admin users get the protected components, while regular users don't get the protected components at all as part of the JS bundle sent to the browser?
Also, this may require a form of code splitting on the front end side. Is code splitting supported in Remix.run?
this is a code snippet from a sample app I wrote, this is the home page and can only be accessed if the user is authenticated.
the redirect(`/login?${searchParams}`) will redirect if the user isn't authenticated
// Loaders provide data to components and are only ever called on the server, so
// you can connect to a database or run any server side code you want right next
// to the component that renders it.
// https://remix.run/api/conventions#loader
export let loader = async ({ request }) => {
const redirectTo = new URL(request.url).pathname;
let session = await getSession(request.headers.get("Cookie"));
// if there is no access token in the header then
// the user is not authenticated, go to login
if (!session.has("access_token")) {
let searchParams = new URLSearchParams([["redirectTo", redirectTo]]);
throw redirect(`/login?${searchParams}`);
} else {
// otherwise execute the query for the page, but first get token
const { user, error: sessionErr } = await supabaseClient.auth.api.getUser(
session.get("access_token")
);
// if no error then get then set authenticated session
// to match the user associated with the access_token
if (!sessionErr) {
// activate the session with the auth_token
supabaseClient.auth.setAuth(session.get("access_token"));
// now query the data you want from supabase
const { data: chargers, error } = await supabaseClient
.from("chargers")
.select("*");
// return data and any potential errors alont with user
return { chargers, error, user };
} else {
return { error: sessionErr };
}
}
};
You can protect routes by authorizing the user inside the loader of the Route, there you could decide to redirect it somewhere else or send a flag as part of the loader data so the UI can hide/show components based on it.
For the code splitting, Remix does it at the route level, but it doesn't support server-side code-splitting out of the box, you may be able to support it with react-loadable.
I hope it has, but not. Below is the official answer.
https://remix.run/docs/en/v1/pages/faq#how-can-i-have-a-parent-route-loader-validate-the-user-and-protect-all-child-routes
You can't 😅. During a client side transition, to make your app as speedy as possible, Remix will call all of your loaders in parallel, in separate fetch requests. Each one of them needs to have its own authentication check.
This is probably not different than what you were doing before Remix, it might just be more obvious now. Outside of Remix, when you make multiple fetches to your "API Routes", each of those endpoints needs to validate the user session. In other words, Remix route loaders are their own "API Route" and must be treated as such.
We recommend you create a function that validates the user session that can be added to any routes that require it.

How do I get the ID of an object from mongodb database in my react application?

I am learning by building. I am building a blog management system using Reactjs, Nodejs, Mongodb.
I would like to store some frontend values in the database so that anyone I give admin permission can post, edit and delete such values. These values are website name, sub-name, sidebar bio description, header image and bio image.
This is the code to create the value:
//create new frontend paramters into database
router.post("/", async (req, res) =>{
const newFrontendValues = new Frontend(req.body);//we called the frontend model we created and we used req.body
try{
const savedFrontendValues = await newFrontendValues.save()//we tried to save the frontend values created
res.status(200).json(savedFrontendValues)
}catch(err){
res.status(500).json(err)
}
});
I wrote the code in node to get the values like this after creating them:
//get frontend parameters
router.get("/:id", async (req, res) =>{
try{
const frontend = await Frontend.findById(req.params.id)
res.status(200).json(frontend)
}catch(err){
res.status(500).json(err)
}
})
my server api code
app.use("/api/frontend", frontend)
In react, I wanted to call the _id of the values but I am lost. I really don't know how to go about that.
It is working fine as desired in postman because I can directly implement the value _id.
See attached image
But in React, I wanted that to be dynamic.
Here is my React code:
useEffect(() => {
const fetchFrontendValue = async () =>{
const res = await axios.get("/frontend")
console.log(res.data)
}
fetchFrontendValue()
}, [])
How do I add the _id to this
axios.get("/frontend")
You'd want to look at get request parameters. Usually as a convention, people pass them in the URL. So it would be something like http://localhost:5000/api/frontend?id=617944dc7e00022337a483be78 and on the API side, you'd use req.body.id to pass that to the database. There are other ways to do it too, but this is the most common because some old browser drop the parameters attached to a GET request. Here's a link:https://www.w3schools.com/tags/ref_httpmethods.asp
You should consider going for a complete solution. On a basic level, you should be following these steps
Implement a backend route /getall that fetch out all items in DB in this manner
await Frontend.find({})
Render the fetched list on frontend side in a way that each item would be a React UI item and as part of each item, you have the buttons for deleting and updating the item data
{backendData?.map((item, index)=><SingleItem key={item?._id} data={item} />)}
As each SingleItem has update and delete buttona and also the mongodb ID as part of data, so on clicking update and delete button, you will get the id from the data and call relevant DB Url on backend side

Capture requests (XHR, JS, CSS) from embedded iframes using devtool protocol

For the context, I am developing a synthetic monitoring tool using Nodejs and puppeteer.
For each step of a defined scenario, I capture a screenshot, a waterfall and performance metrics.
My problem is on the waterfall, I previously used puppeter-har but this package is not able to capture request outside of a navigation.
Therefore I use this piece of code to capture all interesting requests :
const {harFromMessages} = require('chrome-har');
// Event types to observe for waterfall saving (probably overkill, I just set all events of Page and Network)
const observe = [
'Page.domContentEventFired',
'Page.fileChooserOpened',
'Page.frameAttached',
'Page.frameDetached',
'Page.frameNavigated',
'Page.interstitialHidden',
'Page.interstitialShown',
'Page.javascriptDialogClosed',
'Page.javascriptDialogOpening',
'Page.lifecycleEvent',
'Page.loadEventFired',
'Page.windowOpen',
'Page.frameClearedScheduledNavigation',
'Page.frameScheduledNavigation',
'Page.compilationCacheProduced',
'Page.downloadProgress',
'Page.downloadWillBegin',
'Page.frameRequestedNavigation',
'Page.frameResized',
'Page.frameStartedLoading',
'Page.frameStoppedLoading',
'Page.navigatedWithinDocument',
'Page.screencastFrame',
'Page.screencastVisibilityChanged',
'Network.dataReceived',
'Network.eventSourceMessageReceived',
'Network.loadingFailed',
'Network.loadingFinished',
'Network.requestServedFromCache',
'Network.requestWillBeSent',
'Network.responseReceived',
'Network.webSocketClosed',
'Network.webSocketCreated',
'Network.webSocketFrameError',
'Network.webSocketFrameReceived',
'Network.webSocketFrameSent',
'Network.webSocketHandshakeResponseReceived',
'Network.webSocketWillSendHandshakeRequest',
'Network.requestWillBeSentExtraInfo',
'Network.resourceChangedPriority',
'Network.responseReceivedExtraInfo',
'Network.signedExchangeReceived',
'Network.requestIntercepted'
];
At the start of the step :
// list of events for converting to HAR
const events = [];
client = await page.target().createCDPSession();
await client.send('Page.enable');
await client.send('Network.enable');
observe.forEach(method => {
client.on(method, params => {
events.push({ method, params });
});
});
At the end of the step :
waterfall = await harFromMessages(events);
It works good for navigation events, and also for navigation inside a web application.
However, the web application I try to monitor has iframes with the main content.
I would like to see the iframes requests into my waterfall.
So a few question :
Why is Network.responseReceived or any other event doesn't capture this requests ?
Is it possible to capture such requests ?
So far I've red the devtool protocol documentation, nothing I could use.
The closest to my problem I found is this question :
How can I receive events for an embedded iframe using Chrome Devtools Protocol?
My guess is, I have to enable the Network for each iframe I may encounter.
I didn't found any way to do this. If there is a way to do it with devtool protocol, I should have no problem to implement it with nodsjs and puppeteer.
Thansk for your insights !
EDIT 18/08 :
After more searching on the subject, mostly Out-of-process iframes, lots of people on the internet point to that response :
https://bugs.chromium.org/p/chromium/issues/detail?id=924937#c13
The answer is question states :
Note that the easiest workaround is the --disable-features flag.
That said, to work with out-of-process iframes over DevTools protocol,
you need to use Target [1] domain:
Call Target.setAutoAttach with flatten=true;
You'll receive Target.attachedToTarget event with a sessionId for the iframe;
Treat that session as a separate "page" in chrome-remote-interface. Send separate protocol messages with additional sessionId field:
{id: 3, sessionId: "", method: "Runtime.enable", params:
{}}
You'll get responses and events with the same "sessionId" field which means they are coming from that frame. For example:
{sessionId: "", method: "Runtime.consoleAPICalled",
params: {...}}
However I'm still not able to implement it.
I'm trying this, mostly based on puppeteer :
const events = [];
const targets = await browser.targets();
const nbTargets = targets.length;
for(var i=0;i<nbTargets;i++){
console.log(targets[i].type());
if (targets[i].type() === 'page') {
client = await targets[i].createCDPSession();
await client.send("Target.setAutoAttach", {
autoAttach: true,
flatten: true,
windowOpen: true,
waitForDebuggerOnStart: false // is set to false in pptr
})
await client.send('Page.enable');
await client.send('Network.enable');
observeTest.forEach(method => {
client.on(method, params => {
events.push({ method, params });
});
});
}
};
But I still don't have my expected output for the navigation in a web application inside an iframe.
However I am able to capture all the requests during the step where the iframe is loaded.
What I miss are requests that happened outside of a proper navigation.
Does anyone has an idea about the integration into puppeteer of that chromium response above ? Thanks !
I was looking on the wrong side all this time.
The chrome network events are correctly captured, as I would have seen earlier if I checked the "events" variable earlier.
The problem comes from the "chrome-har" package that I use on :
waterfall = await harFromMessages(events);
The page expects the page and iframe main events to be present in the same batch of event than the requests. Otherwise the request "can't be mapped to any page at the moment".
The steps of my scenario being sometimes a navigation in the same web application (=no navigation event), I didn't have these events and chrome-har couldn't map the requests and therefore sent an empty .har
Hope it can help someone else, I messed up the debugging on this one...

How to load data from a different component after submititng form from another component in ReactJs

I have an Event Model. in my event, people can indicate if they are attending an event by clicking a button, and when they indicate that they are attending an event by clicking a button, a Modal dialog will pop up to ask them if they also want to bring friends along to the event, if they say Yes, it will ask them to choose how many people they want to bring and they will choose from a drop-down list of numbers and submit. after submitting everything it will plus people that are coming and how many people the person is coming with then show them together.
Note: the modal dialog is from another component that I am requiring inside my Event component.
the problem that I am facing now is that my view only updates the people that are coming but doesn't update the number of the people the person is bringing along unless I refresh the page. this was working when I was using class-based-component but after changing my code to function based component it stopped working.
How do I make the browser to update it automatically without refreshing the page?
This is my Sandbox link https://codesandbox.io/s/compassionate-sanne-pmmx6?file=/event-comments.component.js
please use this URL inside sandbox https://pmmx6.csb.app/events/
Just add events after the URL provided by sandbox in other to load the events data because the link to the event is not showing inside the sandbox (I don't know why)
Maybe you can solve this by using event emitter
Use
EventEmitter.subscribe('refresh', (event)=>this.refresh(event))
to create the event
And when you want to execute it you use
EventEmitter.dispatch('refresh', event)
Step by step to create a eventEmitter:
Create a eventEmitter.js file:
const EventEmitter = {
events: {},
dispatch: function (event, data) {
if (!this.events[event]) return;
this.events[event].forEach(callback => callback(data))
console.log("Dispatched: " + event)
},
subscribe: function (event, callback) {
if (!this.events[event]) this.events[event] = [];
this.events[event].push(callback)
console.log("Subscribed: " + event)
},
unsubscribe: function(event) {
if (this.events[event]) {
delete this.events[event]
}
console.log("Unsubscribed: " + event)
}
};
module.exports = {EventEmitter};
In the component you want to refresh first you import the eventEmitter.js. For example:
import {EventEmitter} from "./tools/eventEmitter";
Then you use subscribe() to create a event:
EventEmitter.subscribe('refresh', (event)=>this.refresh(event))
where refresh is the function will execute when you dispatch the event
Finally, when you want to refresh the component, use .dispatch():
EventEmitter.dispatch('refresh', event)
This will execute the this.refresh() first component funcion
If you want to look https://medium.com/#lolahef/react-event-emitter-9a3bb0c719 is a good event emitter's page
Thanks, Everyone, I have solved the problem by just adding events after my API call. I saw the example on the React Facebook page. This method reloads the data anytime there is a change.
const [events, setEventData] = useState([]);
useEffect(() => {
axios
.get(
"https://cryptic-shelf-72177.herokuapp.com/events/" +
props.match.params.id +
"/eventcomments"
)
.then((response) => {
setEventData(response.data);
})
.catch(function (error) {
console.log(error);
});
}, [events]);

Resources