pass variables from front to backend - javascript

i have a vue js project with front end and i have a field with variables that i want it when its changed it will go to backend and change there too any idea? the variable is id tage like in this code
app.get('/payments', (request, response) => {
response.set('Access-Control-Allow-Origin','*')
let payments = []
db.collection("payments").where("id", "==", idtag).get().then(snapshot => {
snapshot.forEach((doc) => {
console.log(doc.id, '=>', doc.data())
payments.push(doc.data())
})
response.send(payments)
console.log('payments:',payments)
})
})
and this is the front end
export default defineComponent({
setup () {
const loadinga = ref(false)
const idtag=ref(null)
const filter = ref('')
return {
events: [ '2019/02/01', '2019/02/05', '2019/02/06' ],
date : ref('2019-02-22 21:02'),
columns,
loadinga,
idtag,

Make the ID part of the request url:
// backend assuming this is express
app.get('/payments/:id', (request, response) => {
// use the id in some way
const idtag = req.params.id;
...
});
In your frontend code, you need to watch the idTag and initiate a new request each time it changes.
// frontend
import { defineComponent, ref, watch } from "vue";
export default defineComponent({
setup() {
const idtag = ref(null);
watch(idtag, (newValue, oldValue) => {
fetch(`/payments/${newValue}`)
.then(raw => raw.json())
.then(data => {
// do something with the data
console.log(data)
})
.catch(console.warn);
});
return { idtag };
}
})
If you need this to run immediately, you should use watchEffect instead. But since your value is null at the beginning, I don't think this is the case.

Related

Get path name for NextJS route for dynamic routing?

Is there a way to get the name for the specific route for a page?
I'm getting a list of products and each products gets its own page:
export async function getStaticProps() {
const productCatalog: Array<ProductType> = await getAllProducts()
return { props: { productCatalog } }
}
export async function getStaticPaths() {
const productCatalog: Array<ProductType> = await getAllProducts()
const dynamicFiles: Array<Object> = productCatalog.map(
(product: ProductType) => ({
params: { pid: product.id },
})
)
return {
paths: dynamicFiles,
fallback: false,
}
}
When NextJS generates the static pages, is there a way to get product specific data? I'm currently passing in the entire product catalog in the example then filtering by the single product.
I tried to filter by the route but the router was not recognized. So something like this:
export async function getStaticProps() {
const router: NextRouter = useRouter()
const { pid } = router.query
const productCatalog: Array<ProductType> = await getAllProducts()
const productData: ProductType = productCatalog.filter(
(product: ProductType) => product.id == pid
)[0]
return { props: { productData } }
}
You can access the dynamic page param in getStaticProps through context object's params property. For example, if the page is called [pid].js then you can access context.params.pid:
export async function getStaticProps(context) {
const { pid } = context.params
// Fetch the specific product corresponding to that id
...
}

I am using provide/inject to pass the data within components , I've this function using compute, I am trying to run and pass it's result in provide

I have 4 functions, for 1st three functions, I can send the data in provide. For 4th function(
getViewApplicationDetails
), I am trying to fetch api and get application name, now I want that in mounted because, I want the application name as soon as component is rendered so I am trying to execute it in mounted but when I call the it, it's giving me error. Initially application name is empty and it should have the current application name when I fetch the api, the same application name will be used in provide and then I can use that in inject and then in any other component.
import { computed, inject, onMounted, provide, reactive } from "vue";
export const initStore = () => {
onMounted(()=>{
this.getViewApplicationDetails()
});
// State
const state = reactive({
name: "Bob Day",
email: "bob#martianmovers.com",
applicationName: "",
breadcrumbsData: [
{
name: "Home",
text: 'Home',
disabled: false,
href: '/'
}
]
});
// Getters
const getUsername = computed(() => state.name);
const getEmail = computed(() => console.log("state.email",state.email));
const getBreadcrumbsData=computed(()=>state.breadcrumbsData)
console.log("state.applicationName",state.applicationName)
//this is the temporary function
const getApplicationName=computed(()=>state.applicationName)
const getViewApplicationDetails=computed(()=> {
var viewApplicationDetailsParams = {
applicationId: this.$route.query.applicationId,
applicationStatus:this.$route.query.appStatus,
authType: "api",
clientId: process.env.VUE_APP_EXTERNAL_API_CLIENT_ID,
clientSecret: process.env.VUE_APP_EXTERNAL_API_CLIENT_SECRET
};
axios({
method: "post",
url: process.env.VUE_APP_BLUJ_BACKEND_URL + "/viewapplicationDefinition",
data: viewApplicationDetailsParams,
headers: {
"content-type": "application/json",
},
})
.then((response) =>{
this.viewDefinitionResponse = response.data.Definitions;
let applicationName = viewDefinitionResponse.application_display_name.en;
console.log("tyfgyhkjlfhgjklnm",applicationName)
setApplicationName(applicationName)
})
.catch((error) => {
console.log("error", error);
});
});
getViewApplicationDetails()
// Mutations
const setUsername = (name) => {
state.name = name;
};
const setEmail = (email) => {
state.email = email;
};
const setBreadCrumbsData=(breadcrumbsData)=>{
state.breadcrumbsData=breadcrumbsData;
}
const setApplicationName=(appName)=>{
state.applicationName=appName
}
// Actions
const updateUsername = (name) => {
setUsername(name);
};
const updateEmail = (email) => {
setEmail(email);
};
provide("getUsername", getUsername);
provide("getEmail", getEmail);
provide("updateUsername", updateUsername);
provide("updateEmail", updateEmail);
provide("getViewApplicationDetails", getViewApplicationDetails);
provide("getApplicationName", getApplicationName);
provide("getBreadcrumbsData", getBreadcrumbsData);
};
export const useStore = () => ({
getUsername: inject("getUsername"),
getEmail: inject("getEmail"),
updateUsername: inject("updateUsername"),
updateEmail: inject("updateEmail"),
viewApplicationDetails: inject("getViewApplicationDetails"),
getBreadcrumbsData: inject("getBreadcrumbsData"),
getApplicationName: inject("getApplicationName")
});
This is the code snippet.
const getUsername = computed(() => state.name);
const getEmail = computed(() => console.log("state.email",state.email));
const getBreadcrumbsData=computed(()=>state.breadcrumbsData)
I am getting data for this, but for getViewApplicationDetails, it's not working. While hovering over rest of the functions, it is showing "const getUsername: ComputedRef", like this. But, for getViewApplicationDetails, it shows "const getViewApplicationDetails: ComputedRef", this. I think it is not taking it as function or something. Error image is in the link.enter image description here

When routing mswjs/data populates the database with new items and removes the previous one, making it inaccessible

I use next-redux-wrapper, MSW, #mswjs/data and redux-toolkit for storing my data in a store as well as mocking API calls and fetching from a mock Database.
I have the following scenario happening to me.
I am on page /content/editor and in the console and terminal, I can see the data was fetched from the mock database and hydrated from getStaticProps of Editor.js. So now IDs 1 to 6 are inside the store accessible.
Now I click on the PLUS icon to create a new project. I fill out the dialog and press "SAVE". a POST request starts, it's pending and then it gets fulfilled. The new project is now in the mock DB as well as in the store, I can see IDs 1 to 7 now.
Since I clicked "SAVE" and the POST request was successful, I am being routed to /content/editor/7 to view the newly created project.
Now I am on Page [id].js, which also fetched data from the mock DB and then it gets stored and hydrated into the redux store. The idea is, it takes the previous store's state and spreads it into the store, with the new data (if there are any).
Now the ID 7 no longer exists. And IDs 1 to 6 also don't exist anymore, instead, I can see in the console and terminal that IDs 8 to 13 were created, and the previous ones are no more.
Obviously, this is not great. When I create a new project and then switch the route, I should be able to access the newly created project as well as the previously created ones. But instead, they all get overwritten.
It either has something to do with the next-redux-wrapper or MSW, but I am not sure how to make it work. I need help with it. I will post some code now:
Code
getStaticProps
// path example: /content/editor
// Editor.js
export const getStaticProps = wrapper.getStaticProps(
(store) =>
async ({ locale }) => {
const [translation] = await Promise.all([
serverSideTranslations(locale, ['editor', 'common', 'thesis']),
store.dispatch(fetchProjects()),
store.dispatch(fetchBuildingBlocks()),
]);
return {
props: {
...translation,
},
};
}
);
// path example: /content/editor/2
// [id].js
export const getStaticProps = wrapper.getStaticProps(
(store) =>
async ({ locale, params }) => {
const { id } = params;
const [translation] = await Promise.all([
serverSideTranslations(locale, ['editor', 'common', 'thesis']),
store.dispatch(fetchProjects()),
// store.dispatch(fetchProjectById(id)), // issue: fetching by ID returns null
store.dispatch(fetchBuildingBlocks()),
]);
return {
props: {
...translation,
id,
},
};
}
);
Mock Database
Factory
I am going to shorten the code to the relevant bits. I will remove properties for a project, as well es helper functions to generate data.
const asscendingId = (() => {
let id = 1;
return () => id++;
})();
const isDevelopment =
process.env.NODE_ENV === 'development' || process.env.STORYBOOK || false;
export const projectFactory = () => {
return {
id: primaryKey(isDevelopment ? asscendingId : nanoid),
name: String,
// ... other properties
}
};
export const createProject = (data) => {
return {
name: data.name,
createdAt: getUnixTime(new Date()),
...data,
};
};
/**
* Create initial set of tasks
*/
export function generateMockProjects(amount) {
const projects = [];
for (let i = amount; i >= 0; i--) {
const project = createProject({
name: faker.lorem.sentence(faker.datatype.number({ min: 1, max: 5 })),
dueDate: date(),
fontFamily: getRandomFontFamily(),
pageMargins: getRandomPageMargins(),
textAlign: getRandomTextAlign(),
pageNumberPosition: getRandomPageNumberPosition(),
...createWordsCounter(),
});
projects.push(project);
}
return projects;
}
API Handler
I will shorten this one to GET and POST requests only.
import { db } from '../../db';
export const projectsHandlers = (delay = 0) => {
return [
rest.get('https://my.backend/mock/projects', getAllProjects(delay)),
rest.get('https://my.backend/mock/projects/:id', getProjectById(delay)),
rest.get('https://my.backend/mock/projectsNames', getProjectsNames(delay)),
rest.get(
'https://my.backend/mock/projects/name/:id',
getProjectsNamesById(delay)
),
rest.post('https://my.backend/mock/projects', postProject(delay)),
rest.patch(
'https://my.backend/mock/projects/:id',
updateProjectById(delay)
),
];
};
function getAllProjects(delay) {
return (request, response, context) => {
const projects = db.project.getAll();
return response(context.delay(delay), context.json(projects));
};
}
function postProject(delay) {
return (request, response, context) => {
const { body } = request;
if (body.content === 'error') {
return response(
context.delay(delay),
context.status(500),
context.json('Server error saving this project')
);
}
const now = getUnixTime(new Date());
const project = db.project.create({
...body,
createdAt: now,
maxWords: 10_000,
minWords: 7000,
targetWords: 8500,
potentialWords: 1500,
currentWords: 0,
});
return response(context.delay(delay), context.json(project));
};
}
// all handlers
import { buildingBlocksHandlers } from './api/buildingblocks';
import { checklistHandlers } from './api/checklist';
import { paragraphsHandlers } from './api/paragraphs';
import { projectsHandlers } from './api/projects';
import { tasksHandlers } from './api/tasks';
const ARTIFICIAL_DELAY_MS = 2000;
export const handlers = [
...tasksHandlers(ARTIFICIAL_DELAY_MS),
...checklistHandlers(ARTIFICIAL_DELAY_MS),
...projectsHandlers(ARTIFICIAL_DELAY_MS),
...buildingBlocksHandlers(ARTIFICIAL_DELAY_MS),
...paragraphsHandlers(ARTIFICIAL_DELAY_MS),
];
// database
import { factory } from '#mswjs/data';
import {
buildingBlockFactory,
generateMockBuildingBlocks,
} from './factory/buildingblocks.factory';
import {
checklistFactory,
generateMockChecklist,
} from './factory/checklist.factory';
import { paragraphFactory } from './factory/paragraph.factory';
import {
projectFactory,
generateMockProjects,
} from './factory/project.factory';
import { taskFactory, generateMockTasks } from './factory/task.factory';
export const db = factory({
task: taskFactory(),
checklist: checklistFactory(),
project: projectFactory(),
buildingBlock: buildingBlockFactory(),
paragraph: paragraphFactory(),
});
generateMockProjects(5).map((project) => db.project.create(project));
const projectIds = db.project.getAll().map((project) => project.id);
generateMockTasks(20, projectIds).map((task) => db.task.create(task));
generateMockBuildingBlocks(10, projectIds).map((block) =>
db.buildingBlock.create(block)
);
const taskIds = db.task.getAll().map((task) => task.id);
generateMockChecklist(20, taskIds).map((item) => db.checklist.create(item));
Project Slice
I will shorten this one as well to the relevant snippets.
// projects.slice.js
import {
createAsyncThunk,
createEntityAdapter,
createSelector,
createSlice,
current,
} from '#reduxjs/toolkit';
import { client } from 'mocks/client';
import { HYDRATE } from 'next-redux-wrapper';
const projectsAdapter = createEntityAdapter();
const initialState = projectsAdapter.getInitialState({
status: 'idle',
filter: { type: null, value: null },
statuses: {},
});
export const fetchProjects = createAsyncThunk(
'projects/fetchProjects',
async () => {
const response = await client.get('https://my.backend/mock/projects');
return response.data;
}
);
export const saveNewProject = createAsyncThunk(
'projects/saveNewProject',
async (data) => {
const response = await client.post('https://my.backend/mock/projects', {
...data,
});
return response.data;
}
);
export const projectSlice = createSlice({
name: 'projects',
initialState,
reducers: {
// irrelevant reducers....
},
extraReducers: (builder) => {
builder
.addCase(HYDRATE, (state, action) => {
// eslint-disable-next-line no-console
console.log('HYDRATE', action.payload);
const statuses = Object.fromEntries(
action.payload.projects.ids.map((id) => [id, 'idle'])
);
return {
...state,
...action.payload.projects,
statuses,
};
})
.addCase(fetchProjects.pending, (state, action) => {
state.status = 'loading';
})
.addCase(fetchProjects.fulfilled, (state, action) => {
projectsAdapter.addMany(state, action.payload);
state.status = 'idle';
action.payload.forEach((item) => {
state.statuses[item.id] = 'idle';
});
})
.addCase(saveNewProject.pending, (state, action) => {
console.log('SAVE NEW PROJECT PENDING', action);
})
.addCase(saveNewProject.fulfilled, (state, action) => {
projectsAdapter.addOne(state, action.payload);
console.group('SAVE NEW PROJECT FULFILLED');
console.log(current(state));
console.log(action);
console.groupEnd();
state.statuses[action.payload.id] = 'idle';
})
// other irrelevant reducers...
},
});
This should be all the relevant code. If you have questions, please ask them and I will try to answer them.
I have changed how the state gets hydrated, so I turned this code:
.addCase(HYDRATE, (state, action) => {
// eslint-disable-next-line no-console
console.log('HYDRATE', action.payload);
const statuses = Object.fromEntries(
action.payload.projects.ids.map((id) => [id, 'idle'])
);
return {
...state,
...action.payload.projects,
statuses,
};
})
Into this code:
.addCase(HYDRATE, (state, action) => {
// eslint-disable-next-line no-console
console.group('HYDRATE', action.payload);
const statuses = Object.fromEntries(
action.payload.projects.ids.map((id) => [id, 'idle'])
);
state.statuses = { ...state.statuses, ...statuses };
projectsAdapter.upsertMany(state, action.payload.projects.entities);
})
I used the adapter to upsert all entries.

How to pre-fetch data using prefetchQuery with React-Query

I am trying to pre-fetch data using react-query prefetchQuery. When I am inspecting browser DevTools network tab I can see that data that was requested for prefetchQuery is coming from the back-end but for some reason when I look into react-query DevTools it does generate the key in the cache but for some reason the Data is not there. Let me know what I am doing wrong.
import { useState, useEffect } from 'react';
import { useQuery, useQueryClient } from 'react-query';
import axios from 'axios';
const baseURL = process.env.api;
async function getSubCategoryListByCategoryId(id) {
// await new Promise((resolve) => setTimeout(resolve, 300));
console.log(`${baseURL}/category/subcategories/${id}`);
try {
const { data } = await axios.request({
baseURL,
url: `/category/subcategories/${id}`,
method: 'get',
});
console.log('data getSubCategoryListByCategoryId index: ', data);
return data;
} catch (error) {
console.log('getSubCategoryListByCategoryId error:', error);
}
}
// const initialState = {
// };
const ProductCreate = () => {
const [values, setValues] = useState(initialState);
const queryClient = useQueryClient();
const { data, isLoading, isError, error, isFetching } = useQuery(
'categoryList',
getPosts
);
const dataList = JSON.parse(data);
useEffect(() => {
setValues({ ...values, categories: dataList });
dataList.map((item) => {
console.log('useEffect values.categories item.id: ', item._id);
queryClient.prefetchQuery(
['subCategoryListByCategoryId', item._id],
getSubCategoryListByCategoryId(item._id)
);
});
}, []);
return <h1>Hello</h1>;
};
export default ProductCreate;
The second parameter to prefetchQuery expects a function that will fetch the data, similar to the queryFn passed to useQuery.
But here, you are invoking the function, thus passing the result of it into prefetchQuery:
getSubCategoryListByCategoryId(item._id)
if you want to do that, you can manually prime the query via queryClient.setQueryData, which accepts a key and the data for that key passed to it.
otherwise, the fix is probably just:
() => getSubCategoryListByCategoryId(item._id)

How do you pass a react component's props down to options after apollo-client mutation?

How do you pass a react component's props down to options after apollo-client mutation?
I am using react with apollo-client. In a component I am trying to run a delete mutation after which I want to remove the item from the local store without doing a refetchQueries. In order to do so I've been using the options.update command.
In order to update the store, I need the parent ID of the object I'm trying to delete. It's available in the react component, I just need to find a way to pass it down to the options.update function.
const { fundId } = this.props;
const variables = { documentId: document.id };
const options = { variables }
this.props.deleteFundDocument(options)
.then( response => console.log("Document successfully deleted", response) )
.catch( e => console.log("Document not deleted", e) )
export default graphql(FundDocumentQL.deleteFundDocument, {name: 'deleteFundDocument', options: FundDocumentQLOptions.deleteFundDocument})
)(DocumentDisplay)
Here's what I pass in to the options from FundDocumentQLOptions as you can see I get the fundId from localStorage which is kind of hacky. I'd rather try and pass it down properly.
const deleteFundDocument = {
update: (proxy, {data: {deleteFundDocument}}) => {
try {
if (localStorage.getItem('documentViewerFundId')) {
const fundId = localStorage.getItem('documentViewerFundId');
let data = proxy.readQuery({query: FundDocumentQL.allFundDocuments, variables: {fundId: fundId}});
console.log('data.allFundDocuments 1', data.allFundDocuments);
// console.log('documentId', documentId);
console.log('variables.documentId', variables.documentId);
const newDocuments = data.allFundDocuments.filter( item => {
return item.id !== deleteFundDocument.id;
});
console.log('newDocuments', newDocuments);
data.allFundDocuments = [...newDocuments];
console.log('data.allFundDocuments 2', data.allFundDocuments);
proxy.writeQuery({query: FundDocumentQL.allFundDocuments, data, variables: {fundId: fundId}});
}
} catch (e) {
console.log(e);
}
}
};
I saw this example in the apollo-client docs:
https://www.apollographql.com/docs/react/basics/mutations.html#graphql-mutation-options-variables
export default graphql(gql`
mutation ($foo: String!, $bar: String!) {
...
}
`, {
options: (props) => ({
variables: {
foo: props.foo,
bar: props.bar,
},
}),
})(MyComponent);
And I saw this answer:
Apollo can't access queryVariables in update: after a mutation
Reading the other answer here Apollo can't access queryVariables in update: after a mutation
I realized I could pass fundId from this.props into the update function when I created the options object ahead of the mutation.
const { fundId } = this.props;
const variables = { documentId: document.id };
const options = {
variables: variables,
update: (proxy, { data: { deleteFundDocument } }) => FundDocumentQLOptions.deleteFundDocument(proxy, deleteFundDocument, fundId)}
this.props.deleteFundDocument(options)
.then( response => console.log('Document successfully deleted', response) )
.catch( e => console.log('Document not deleted', e) )
export default graphql(FundDocumentQL.deleteFundDocument, {name: 'deleteFundDocument'})(DocumentDisplay)
From FundDocumentQLOptions
const deleteFundDocument = (proxy, deleteFundDocument, fundId) => {
try {
let data = proxy.readQuery({query: FundDocumentQL.allFundDocuments, variables: {fundId: fundId}});
// console.log('data.allFundDocuments 1', data.allFundDocuments);
data.allFundDocuments = data.allFundDocuments.filter( item => {
return item.id !== deleteFundDocument.id;
});
// console.log('data.allFundDocuments 2', data.allFundDocuments);
proxy.writeQuery({query: FundDocumentQL.allFundDocuments, data, variables: {fundId: fundId}});
} catch (e) {
console.log(e);
}
};

Categories

Resources