express routes share variable - express

I can't share var between routes in my index.js. I need to use var page from first route in the second route. Is necesary a closure for this? I have this two routes:
First route:
router.get('/:page', async (req, res, next) =>{
var perPage = 5;
var page = req.params.page || 1;
console.log(page);
const expedientes = await Expediente
.find()
.skip((perPage*page)-perPage)
.limit(perPage)
.exec((err, expedientes)=> {
Expediente.count().exec((err, count)=> {
if (err) return next(err)
res.render('index', {
expedientes,
current: page,
pages: Math.ceil(count / perPage)
})
})
})
});
Second route:
router.get('/select/:id', async (req,res) => {
const { id } = req.params;
const {path} = req.path;
const expediente = await Expediente.findOne({selected:true});
const expediente2 = await Expediente.findById(id);
if (expediente){
expediente.selected=!expediente.selected;
await expediente.save();
}
expediente2.selected=!expediente2.selected;
await expediente2.save();
res.redirect('/1');
});
I need to use var page for the last line of the second route. How can i get that value to use it? I have try:
res.redirect('/'+ page);
but it doesn't work.
Some information about this problem?

You should probably avoid keeping the front-end state in your backend. In order to avoid this you can introduce a query parameter with the redirect
router.get('/select/:id', async ( req, res ) => {
const { id } = req.params;
const {path} = req.path;
const expediente = await Expediente.findOne({selected:true});
const expediente2 = await Expediente.findById(id);
const page = req.query.page;
if (expediente){
expediente.selected=!expediente.selected;
await expediente.save();
}
expediente2.selected=!expediente2.selected;
await expediente2.save();
res.redirect('/' + page);
});
Then you should call the URL with /select/2?page=1 which will redirect you to the page.
In your solution when you have two routes called by two different clients will have the very same page being defined, which is not what you probably want.

The solution is not easy. In my app I have two different needs. Both, need to obtain data from the database.
The first is pagination, each time a pagination-button is pressed, the database must be consulted to obtain the set of records for that page-pagination.
The second is the record-selection, it also need the database because when you select a record the id is stored so that the delete and edit buttons can act. All this works perfectly.
But the problem is when I select a record and also I advance in the pagination and select again other record. when the page is loaded again, I can not find a way to redirect back to the page from which it came. That is the page-pagination where the second record was selected.
So I thought that saving the last page in a variable, I could use that variable to redirect back in other route.
My question therefore is: can I save res.params.page in a variable and then use that varible in a different route?

Related

Fresh Framework: Fetching to own api results in "URL not found"

In my "/yourPage" route, my handler is trying to fetch "/api/joke" from my local database. I get "URL not found" error. Since Fresh is server rendered, I'd like to get all the data I need when loading the first time.
This works fine when fetching after initial load (like with a button).
As per its documentation, it should work fine, and does for any API that is not in its own repository.
Any way I can make this work? Am I thinking of this the wrong way?
The fetch inside my handler:
routes/yourPage.ts
export const handler: Handlers = {
async GET(req, ctx) {
const joke = await getJokes()
return ctx.render(joke);
},
};
/routes/api/joke.ts
const JOKES = [
"Why do Java developers often wear glasses? They can't C#.",
"A SQL query walks into a bar, goes up to two tables and says “can I join you?”",
];
export const handler = (_req: Request, _ctx: HandlerContext): Response => {
const randomIndex = Math.floor(Math.random() * JOKES.length);
const body = JOKES[randomIndex];
return new Response(body);
};
Pretty old post, but this is the first StackOverflow Google result when you try to search for API calling in Fresh Framework.
I am assuming you imported inside routes/yourPage.ts the handler from /routes/api/joke.ts as this:
import { handler as getJokes } from "./api/joke.ts";
Inside routes/yourPage.ts you also have to extract the text/json from the response before using it:
export const handler: Handlers = {
async GET(_req, _ctx) {
const response = getJokes(_req, _ctx);
const jokeText = await response.text();
return _ctx.render(jokeText);
},
};
Then you can use the response in your page as:
export default function Home({ data }: PageProps) { //...
Documentation here:
https://fresh.deno.dev/docs/getting-started/fetching-data

res.redirect() unexpected behaviour

Both of these blocks of code redirect to products/:id. However, the path I have to introduce is different.
in the post route I have to include products/, but in the put route I don't.
Does anybody know why this is the case? Thank you for your time.
router.post("/", async (req, res) => {
const newProduct = new Product(req.body)
await newProduct.save()
console.log(newProduct)
res.redirect(`products/${newProduct.id}`)
})
router.put("/:id", async (req, res) => {
const { id } = req.params
const product = await Product.findByIdAndUpdate(id, req.body,
{
runValidators: true,
new: true
})
console.log(req.body)
res.redirect(`${product._id}`)
}
Redirections happen relative to the URL of the request that triggered them.
The POST route is triggered by POST /products.
The PUT route is triggered by PUT /products/123.
Relative evaluation effectively replaces the last segment of the triggering URL with the relative URL. This can be demonstrated with the URL class in Node.js:
> new URL("newid","http://server/products").href
'http://server/newid'
> new URL("products/newid","http://server/products").href
'http://server/products/newid'
> new URL("id","http://server/products/id").href
'http://server/products/id'

Preload Multiple Fetch Calls in Vue 3 App

I have a relatively small app that I would like to call multiple api's as the app gets loaded initially and store those results (without Vuex) so that it could be made available via provide/inject to child components.
In my App.vue currently, I have this:
export default {
setup() {
const data = ref([]);
const issues = ref([]);
(async () => {
const res = await fetch("/api/lists").then({ data });
data.value = await res.json();
data.value =
data.value &&
data.value.data.map((c) => {
return { ...c.attributes, id: c.id };
});
})();
(async () => {
const res = await fetch("/api/issues").then({ issues });
issues.value = await res.json();
issues.value =
issues.value &&
issues.value.data.map((c) => {
return [{ ...c.attributes, id: c.id }];
});
})();
provide("items", data);
provide("issues", issues);
return {};
},
components: {},
The items data get's rendered 100% of the time in the child component. The issues data get's rendered maybe 10% of the time and I'm assuming it's because the async function doesn't finish before the provide statements run.
My questions are
Is there a better way to call multiple fetch statements at once and assign those results to a variable I can "provide?"
What's the best way to preload these api calls (there's about 3 or 4 more I need to implement) when a user first visits the site and have the results made available without having to re-fetch every time a user switches between views and without using Vuex.
You can do it like this: https://stackblitz.com/edit/vue-y5hetf
Promise.all is for running the fetch calls in parallel, instead of doing it serially which helps improving performance.
As long as you are doing those requests in the App.vue file, these calls should only happen on reload, not on route changes.

Vue redirecting. My code is note redirecting to the page i want to

it is not redirecting to the page. What am I doing wrong here?
this method is getting all the data from the form and adding dynamic values to date and token.
methods:{
addToApi() {
console.log(this.data);
crypto.randomBytes(20,(err,buff)=>{
let token = buff.toString('hex');
let sub = this.data.sub;
let date = Date.now() + 3600000;
let newData = {
sub: this.data.sub,
token: token,
date: date
}
axios.post("http://localhost:3000/api/qrData",newData)
.then((res)=>{
//after sending the data to back end it should redirect to this route but it doesn't redirect
router.go('/');
})
.catch((err)=>{
console.log(err);
})
})
}
}
}
check Vue Router: Programing Navigation,
As the tutorial said:
router.go(n)
This method takes a single integer as parameter that indicates by
how many steps to go forwards or go backwards in the history stack,
similar to window.history.go(n).
For your use case, you should use router.push
The main problem is that you refer to this variable which in this certain case has different values over the scopes. The common solution is to create a new variable storing this as I did it in the first line of addToApi() method.
Getting to the point, variable router is undefined in the method's scope. You should use this.$router which refers to the global router object. And as this variable loses its value in then function (change of scope), you want to use vm variable I defined. So your code should finally look like this below:
As pointed in the comment, arrow functions do not carry this variable.
If you want to redirect to a particular route you should use $router.push method instead. (go method was used in Vue Router's older versions and renamed to push in 2.x)
methods: {
addToApi() {
crypto.randomBytes(20, (err, buff) => {
let token = buff.toString('hex');
let sub = this.data.sub;
let date = Date.now() + 3600000;
let newData = {
sub: this.data.sub,
token: token,
date: date
}
axios.post("http://localhost:3000/api/qrData", newData)
.then((res) => {
//after sending the data to back end it should redirect to this route but it doesn't redirect
this.$router.push('/');
})
.catch((err) => {
console.log(err);
})
})
}
}
}

How to bind context to async storage using React Native

I have a list of items. users can like them.
I use AsynStorage to store the state. It works.
Only, I can't bind the storage to a specific item. If I like/dislike an item, the same thing happen for all of them. Here is the code, an idea ?
componentWillMount() {
this._renderSwitchButtonWithAsyncStorage().done;
}
_renderSwitchButtonWithAsyncStorage = async() => {
let token = await AsyncStorage.getItem('AlreadyLiked');
if (token){
this.setState({trueSwitchIsOn: true});
}else{
this.setState({trueSwitchIsOn: false});
}
};
onPressIcon(word){
AsyncStorage.setItem('AlreadyLiked', JSON.stringify({trueSwitchIsOn}));
}
I got it, thank you:
onPressIcon(word){
const { _key} = this.props.navigation.state.params;
AsyncStorage.setItem(JSON.stringify({_key}),JSON.stringify({trueSwitchIsOn}));
//Check if token exists
_renderSwitchButtonWithAsyncStorage = async() => {
const {_key} = this.props.navigation.state.params;
let token = await AsyncStorage.getItem(JSON.stringify({_key}));
Use Different AsyncStorage key name,
If you use same name to affect the all users so each users has use different key