Displaying array-responses in the form of a Nested menus using React - reactjs

I'm fairly new to React and stuck regarding a very minor problem. I wrote an UI that essentially calls a service that returns the responses in the form of an array. Now, I need those responses from the service to be displayed in the form of a nested menu. For e. g., one of my axios calls returns a response of [1,2,3,4] and the other axios call returns [1.1,1.2,1.3,..]. I want these responses to be aligned in the form of
1
1.1
1.2
1.3
2
2.1
etc.,
i. e. the UI should show 1,2,3,4 .. and when the user clicks on 1, then 1.1,1.2 etc. should be displayed.
I'm using React, material-ui's components and redux for this.
I have a function to do the above mentioned.. but I'm not sure if I'm doing it right.
handleMenuData() {
var applist = this.props.menuData;
var appNames = [];
var moduleNames = [];
applist.forEach(app => {
app.moduleNames.forEach(module => {
try {
return axios.get(
'service url' + app.name + '/' + module,
);
} catch (error) {
console.error(error);
}
});
appNames.push({
name: app.name,
moduleNames: moduleNames,
});
moduleNames = [];
});
this.setState({
appNames: appNames,
});
}
and in my state,
this.state = {
appList: [],
appNames: [],
moduleNames: [],
};
app names are 1,2,3 and module names are 1.1,1.2 and I was thinking of using ListItemText component from material UI.

I think what you are doing is incorrect. axios.get is an asynchronous function and you are not waiting for the response to come from the server. That's why you get all arrays as empty. Try calling a recursive function like this.
const getModuleNames = (i) => {
axios.get('service url' + applist[i].name + '/' + module)
.then((response) => {
if(i < applist.length){
applist[i].moduleNames = response.data;
appNames.push({
name: applist[i].name,
moduleNames: applist[i].moduleNames
});
getModuleNames(i++);
}
else {
// code you want to execute after adding data to appNames
}
}).catch((err) => {
// error handling
});
}
getModuleNames(0);

Related

SvelteKit form get request

I am trying to set up a simple endpoint in SvelteKit that reads the input given in a form and returns the result of an SQL query. In my first attempt I used the form actions and wrote the following code in the +page.server.js file:
export const actions = {
default: async (event) => {
let form_input = await event.request.formData();
let query = {
text: "select * from ux_return_shipments($1, $2, $3, $4)",
values: [form_input.get('beg-dep-date') || null, form_input.get('end-dep-date') || null, form_input.get('beg-arr-date') || null, form_input.get('end-arr-date') || null
}
try {
const result = await event.locals.pool.query(query);
return result.rows;
} catch (e) {
console.log(e);
}
}
};
I am now trying to set up the same process using a GET request instead of a POST one but I am having difficulties setting up the endpoint. I tried to replace the above code with this template but it looks like the endpoint is not getting activated since I see no activity server side:
export function GET({ url }) {
console.log(url);
return new Response("Test response");
};
What am I doing wrong? I see that using this code for an API endpoint (+server.js file) works correctly. I also checked the form element and the URL looks correct.
In case someone has the same problem I managed to solve it using this template:
export const load = async (event) => {
return ...
};
Using the load function I was able to set up a get endpoint and pass some data to the frontend using a return.

how to lazy load only once in react

I am lazy loading service file dynamically on demand from a method, which gets called multiple times and i have to wait until i get response even though i had loaded that file before. Can i load it only once?
processData(serviceName: any, methodName: any) {
import(`./${serviceName}Service`)
.then(component =>{
var result = component.default[methodName] ? component.default[methodName]() : [];
}
})
.catch(error => {
console.error(`Model not yet supported` + error);
return null;
});
}
}
I have written above method to dynamically lazy load service file, it works fine. But processData() gets called many times(onchange of any control) and most of the times the files would have already imported once.
I do not want to load that file again. How or where can i implement this? I will not get serviceName parameter until home page route is called.
where can i lazy load import and use it forever in application?
You can do it by using a name-spaced object.
const servicesCache = {};
processData(serviceName: any, methodName: any) {
if (servicesCache[serviceName]) {
var result = servicesCache[methodName];
} else {
import (`./${serviceName}Service`)
.then(component => {
servicesCache[serviceName] = component.default[methodName] ? component.default[methodName]() : [];
var result = servicesCache[serviceName];
})
.catch(error => {
console.error(`Model not yet supported` + error);
return null;
});
}
}

Ionic Native contacts spent a lot of time and blocks UI

I am developing with Ionic + Capacitor + React and I need to read all contacts numbers.
Using ionic-native/contacts in this way:
import { Contacts, ContactFindOptions } from '#ionic-native/contacts';
...
loadContacts() => {
this.setState(
{
loading: true,
},
() => {
var contacts = new Contacts();
const desiderFields = ['phoneNumbers'];
var options = new ContactFindOptions();
options.filter = '';
options.multiple = true;
options.hasPhoneNumber = true;
contacts.find(desiderFields, options).then((result) => { ... } );
});
}
componentDidMount() {
this.loadContacts();
}
But as soon as loadContacts start reading contacts the UI blocks and not even the state has time to render to show the loader.
Plus, the it is very slow importing contacts, showing repeatedly Fetching in bulk 250 contacts!.
I know that cordova-plugin-contacts is deprecated but I can't believe that those not exists valide alternatives to this fundamental feature.
Can't find solution.
I found this cordova plug-in that saved my life:
https://github.com/dbaq/cordova-plugin-contacts-phone-numbers

React js Axios Get Request in submit form

i have a simple input form where i put a list of strings , then for each element of the string (string[i]) i run an ajax Get request to my api .
so here is the ajax request :
async function getUsers(props){
try{
const response = await Axios.get(`url=`+props)
console.log(response)
return response;
}catch{
console.log("response failed")
}
}
and i run it here :
... some code here ...
for(var i =0; i < string.length; i++){ // map the entery (string)
getUsers(string[i]).then(res => {
this.setState({
string2:res // this one is just for testing
});
console.log(res.data.id);
mystring22.push({res});
console.log("me inside the promise : " + this.state.string2.data.id);
})
setTimeout(() => {
console.log("iam not empty " + this.state.string2.data.id);
console.log(mystring22);
/* -----------------
I WANT TO DO SOME WORK HERE
-----------------*/
}, 3000);
this.setState({
string3 : mystring22
})
... some code here ...
so everything works fine , and my problem is the following :
the code take too much time (3 second for each request ) , is there is a way to change the code so it can do "SOMETHING" after each request , i tried to delete the setTimeout or reduce it but that not working the array is undefined after that .
hope you can help me .
thank you
setState is an async function, so when you call:
setState({ string2: res });
this.state.string2; // OUTDATED
in order to access the updated value, you must use the callback:
setState({ string2: res },
() => { console.log(this.state.string2) }); // UP TO DATE
as you can see in this codesandbox example, with the callback on line 27 and without the callback on 33.

Is it possible to use the Symfony form component with React.js?

I am using the Symfony form component. I have many forms in my project.
To perfectly learn the form component was a long way to go, but now I love it. I love also the automatic validation and so on.
So. now I want to learn and use React.js in my project.
But it seems, there is no way I can use the validation and form builder like before for the projects? Am I right there?
While, in an API context, you won't use the Form Component to actually render your form in HTML format ($form->createView() method), you can still benefit from all the magic it offers: validation, form events, etc. API or not, I personnally think you should always use Form Types in Controller mutations.
For example, using FOSRestBundle, consider some simple Controller action looking like this:
/**
* #Rest\Put("posts/edit/{id}", name="posts.edit", requirements={"id"="\d+"})
*
* #param Post $post
* #param Request $request
*
* #return Post
*
* #throws BadRequestException
*
*/
public function edit(Post $post, Request $request): Post
{
$form = $this->createForm(PostType::class, $user);
$form->handleRequest($request);
$form->submit($request->request->all());
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($post);
$em->flush();
return $post;
}
// Any error handling of your taste.
// You could consider expliciting form errors.
throw new BadRequestException();
}
Note that Post entity and PostType form must be created, of course. I won't be detailing it here as there is nothing special to say about them in this context.
Also note that we don't check if the form is submitted. Rendering the form as HTML being React's job in your case, this action won't be used to GET anything, it is exclusively a PUT route. This means that any Request coming there MUST be a PUT Request containing the correct data to be handled by our PostType, submitted in your case by an HTML form manually built in React.
Furthermore, slightly out of the question's scope, FOSRestBundle subscribes to whatever your action returns and automatically serializes it to the configured format (let's say JSON in your case, I guess). This means that our example of action can return two possible responses:
A Response with status code 200 containing our serialized Post. (You could also consider a 204 and return nothing.)
A Response with status code 400 containing whatever we want (let's say form errors).
Allow me to lead you to the FOSRestBundle's documentation.
You can use your form created with the formBuilder without problem.
You must get your form with axios and create a new component like this:
const url = 'localhost/post/new';
const ref = useRef(null);
const [form, setForm] = useState('');
const fetchData = () => {
axios.get(url))
.then(function (response){
setForm(response.data);
})
.catch(function (error){
//something
})
;
}
const MyComponent = () => {
useEffect(() => {
const element = ref.current.firstChild;
if (ref.current.firstChild === null)
return;
element.addEventListener('submit', () => {handleSave(event)});
return () => {
element.removeEventListener('submit', () => {handleSave(event)});
};
}, []);
return (
<div ref={ref} dangerouslySetInnerHTML={{ __html: form }} />
);
};
const handleSave = (event) => {
event.preventDefault();
let formData = new FormData(event.target)
let action = event.target.action;
let files = event.target.querySelectorAll('[type="file"]');
if (files)
files.forEach((file) => {
formData.set(file.name, file.files[0])
});
axios.post(action, formData)
.then(function (response) {
Swal.fire({
icon: 'success',
title: response.data.message,
showConfirmButton: false,
timer: 1500
})
//Do something else
})
.catch(function (error) {
error.response.status === 422 ?
setForm(error.response.data)
:
console.log(error);
});
}
return (<MyComponent/>);
So, now you can get the form with html components and render it with the React Component.
If you get some validation error you get a 422 status and you can replace the form with setForm().
In your Symfony Controller you must set something like this:
#[Route('/post/{state}/{id}', name: 'post', defaults: ['state' => null, 'id' => null])]
public function post(
?string $state,
?int $id,
Request $request,
EntityManagerInterface $em
): JsonResponse|Response
{
if ($state == 'new') {
$post = new Post();
$form = $this->createFormBuilder()
->add('title', TextType::class)
->add('content', TextareaType::class);
$form = $form->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() and $form->isValid()) {
$em->persist($post);
$em->flush();
return $this->json(['message' => 'post added!'], 200);
}
return $this->renderForm('{{ form(form) }}', [
'form' => $form
]);
}
}
I have reduced the function only for the form, but you can use it for all your requests.
Probably not because your form is intended for server use: validation/show errors/data normalization/sanatization/etc.
Usually you use React to display HTML and connect it to your server using an API.

Resources