POST request returning old data ReactJS - javascript

I am trying to recreate google translate, I have an api which sends data as expected, also returns data as expected the first time. After changing text and trying to translate it, it sends the changed text but returns old data from the first api request.
Here's the code:
const encodedParams = new URLSearchParams();
const inputClick = (key) => {
console.log("input key is: ", key)
encodedParams.append("from", key)
};
const outputClick = (key) => {
console.log("output key is: ", key)
encodedParams.append("to", key)
};
const options = {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
"X-RapidAPI-Key": "...",
"X-RapidAPI-Host": "translo.p.rapidapi.com",
},
body: encodedParams,
};
const translate = () => {
let inp = document.getElementById("input-txt").value;
encodedParams.append("text", inp)
console.log("input text: ", inp)
fetch("https://translo.p.rapidapi.com/api/v3/translate", options)
.then((response) => response.json())
.then((response) => {
console.log(response)
console.log("translated text: ", response.translated_text)
})
.catch((err) => console.error(err))
}
Here's the data it returns:
input key is language I am translating FROM (here it is bosnian),
output key is language I am translating TO (here it is english),
first input text is correct and should translate to "Greetings from Bosnia" which it does,
second input text is modified and correct which should translate to "Greetings from Croatia" which it does not translate to.
I am out of ideas.
EDIT
encodedparams is declared on start I just failed to copy it correctly
Here's extra code
Following code is for inputClick, this is where I choose one of the languages from dropdown menu, the languages.map is extracting array of available languages from other js file which I imported. the language.code is ISO 639-1 code for selected language:
<ul className="dropdown-menu">
{languages.map((language) => (
<li>
<button
className="dropdown-item"
type="button"
onClick={() => inputClick(language.code)}
key={language.code}
>
{language.name}
</button>
</li>
))}
</ul>
Following code is for input text, this is where I type text that I want to be translated which is obtained with getElementById:
<div className="input-txt layout">
<textarea
type="text"
id="input-txt"
placeholder="Unesite vaš tekst ovdje..."
/>
</div>
Following code is outputClick, same explanation as inputClick just for output:
<ul className="dropdown-menu">
{languages.map((language) => (
<li>
<button
className="dropdown-item"
type="button"
onClick={() => outputClick(language.code)}
key={language.code}
>
{language.name}
</button>
</li>
))}
</ul>
Following code is for button which calls translate() on click:
<button
type="button"
className="btn btn-dark trans-btn"
onClick={() => translate()}
>
Prevedi
</button>
*Prevedi means Translate

Problem has been solved by going into Network and seeing what was exactly going to api, the following image will make you understand better:
When sending the first time the text is APPENDED to encodedParams and is sent correctly. The problem lies when I APPEND another text without clearing previous one which creates problem where both texts are sent, and if I change the text for the third time the last two texts are sent with the new one and just goes on and on, you can see it in this image:
Seems like api only takes first text and doesn't go to the last one and take that instead.
Anyways this problem is solved by clearing the appended text after fetch by adding next line:
encodedParams.delete("text", inp)
The function looks like this now:

Related

I can't get my Post request to have the values I think they should have

I did a build along to make a twitter tweet box. It has html css and js. The character count portion seems to work great. But when I try to send the value of the text area as a POST request, the json payload comes back as None. When I hit the server from Postman, it seems to work just fine. I don't know how much of the code I should include. So please let me know. I don't want to put the whole thing and make it unreadable. I'll include the parts I think make sense to include.
<div class="wrapper">
<form action="{{ url_for('thread_builder') }}" method="post">
<div class="input-box">
<div class="tweet-area">
<span class="placeholder">What's happening?</span>
<div class="input editable" contenteditable="true" spellcheck="false"></div>
<div id="text" class="input readonly" contenteditable="true" spellcheck="false"></div>
</div>
const textarea = document.getElementById("tweet-area");
const button = document.getElementById("tweetButton");
const counter = document.getElementById("counter");
const readonlyInput = document.getElementById("readonlyInput");
const maxLength = 280;
button.addEventListener("click", function() {
let text = textarea.value;
let currentLength = text.length;
if (currentLength <= maxLength) {
// send text to the server using fetch
fetch('/thread_builder', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ "text": text })
})
.then(response => response.json())
.then(data => {
// handle the response from the server here
})
.catch(error => {
// handle error here
});
}
I tried sending the POST request from POSTMAN and it worked great. I've tried check what type of information is being sent, and I was expecting a string with what was entered in the text box.enter code here

React.js - Done a API fetch that renders all items, now I want to be able to route on each item to their "own" page with JSON info

I have created an React site that renders all items inside an API Fetch on a page. What I want now is to be able to press each item that renders and be able to get routed to a new component that shows "more" info about that item.
Below I have the following code that takes in the "input" that you can use to search for all items or for a specific item.
const AgentSearch = (e) => {
e.preventDefault();
function capitalizeName(input) {
return input.replace(/\b(\w)/g, (s) => s.toUpperCase());
}
console.log('you hit search', input);
dispatch({
type: actionTypes.SET_SEARCH_TERM,
term: capitalizeName(input),
});
//do something with input
history.push('/findagent');
};
return (
<form className='search'>
<div class='search__input'>
<SearchIcon className='search__inputIcon' />
<input value={input} onChange={(e) => setInput(e.target.value)} />
</div>
Here is the code that renders all items:
eachName = data.map((item) => {
return (
<tr>
<td class='text-left'>{item.name}</td>
<td class='text-left'>{item.agency}</td>
</tr>
);
});
Basically what I would like to do is to "catch" the {item.name} and put that into a new query into the fetch once you press that item on the list that got created.
I tried to create a button that covers the whole class and then put {item.name} as input, but that does not work, also tried to make a "fake" input window that has the {item-name} stored for each item on list, even though the {item-name} gets onto the input window, once i push the button that its connected to, it says it doesn't have any value.
Does anyone know of any clean idea for this? I'm new to React so this might be really easy, haha.
Thanks!
The simplest way is to do onCLick on the td. See the code below.
const eachName = data.map((item) => {
return (
<tr>
<td class='text-left' onClick={() => handleNameClick(item.name)}>{item.name}</td>
<td class='text-left'>{item.agency}</td>
</tr>
);
});
You can define the handleNameClick function. You'll get the item.name as the parameter. See below.
const handleNameClick = itemName => {
//your code to send request for the clicked name
}

Saving Values to Backend from TextBoxes using React Flux Pattern

I have several text boxes and a save button
Each text box value is loaded using the following approach
{
this.getElement('test3lowerrangethreshold', 'iaSampling.iaGlobalConfiguration.test3lowerrangethreshold',
enums.IASamplingGlobalParameters.ModerationTest3LowerThreshold)
}
private getElement(elementid: string, label: string, globalparameter: enums.IASamplingGlobalParameters): JSX.Element {
let globalParameterElement =
<div className='row setting-field-row' id={elementid}><
span className='label'>{localeHelper.translate(label)}</span>
<div className="input-wrapper small">
<input className='input-field' placeholder='text' value={this.globalparameterhelper.getDataCellContent(globalparameter, this.state.globalParameterData)} />
</div>
</div>;
return globalParameterElement;
}
Helper Class
class IAGlobalParametesrHelper {
public getDataCellContent = (globalparameter: enums.IASamplingGlobalParameters, configdata: Immutable.List<ConfigurationConstant>) => {
return configdata?.find(x => x.key === globalparameter)?.value;
}
}
This works fine. Now the user is allowed to update these text values.And on click of save the changes should be reflected by calling a web api .
I have added an onlick event like this
<a href='#' className='button primary default-size' onClick={this.saveGlobalParameterData}>Save</a>
Now inorder to save the data i need a way to identify the text element which has changed.For that i have added an update method within the Helper class
public updateCellValue = (globalparameter: enums.IASamplingGlobalParameters, configdata: Immutable.List<ConfigurationConstant>,updatedvalue:string) => {
let itemIndex = configdata.findIndex(x => x.key === globalparameter);
configdata[itemIndex] = updatedvalue;
return configdata;
}
and return the updated configdata ,and i plan to call this method in the onchange event of every text box like this
<input className='input-field' placeholder='text' onchange={this.setState({ globalParameterData: this.globalparameterhelper.updateCellValue(globalparameter, this.state.globalParameterData, (document.getElementById(elementid) as HTMLInputElement).value})}
But this does not seem like a correct approach as there are number of syntactical errors. I initially got the data using an actioncreator like this.Please advice.
samplingModerationActionCreator.getGlobalParameters();
samplingModerationStore.instance.addListener(samplingModerationStore.SamplingModerationStore
.IA_GLOBAL_PARAMETER_DATA_GET_EVENT,
this.getGlobalParameterData);
}

ForkJoin() issue on Angular

Hello I am currently working on an UI and I need to print for each 'digId' a value that I retrieved in an unique JSON response.
In the case below, I have 3 incidents and I did a fork to have access to the 3 JSON response.
digId='4149';
digId2='4719';
digId3='4309';
ngOnInit(): void {
const parallel$ = Observable.forkJoin(
this.http.get('http://ninjaopsapi?tablename=REF_OPS_ALARM&babylonref=' + this.digId),
this.http.get('http://ninjaopsapi?tablename=REF_OPS_ALARM&babylonref=' + this.digId2),
this.http.get('http://ninjaopsapi?tablename=REF_OPS_ALARM&babylonref=' + this.digId3)
);
parallel$.subscribe( data => {
this.alarms = data, console.log(data);
})
}
My goal is to print the element circled in blue for example: Capture
But with this code below in my html, I retrieve the element [0] for the three incidents and I can't put an additionnal [0] to select only one.
<div *ngFor= "let alarm of alarms">
<div [(ngModel)]="digId" ngDefaultControl>
<div>{{alarm[0].alertMessage}}</div>
</div>
</div>
Is it possible to print the first element of the first element in an array when the .subscribe is done with a "forkJoin()" ?
Thank you
UPDATE
I only changed {{alarm[0][0].alertMessage}} by {{alarms[0][0].alertMessage}} and delete the loop *ngFor="let alarm of alarms
and it works well ! Thank you
You could simply do
parallel$.subscribe( data => {
this.alarms = data.map(x => x[0]);
});
<div>{{alarm.alertMessage}}</div>

React dynamically create buttons based on number of results

I am working in a Spring application that uses react. Currently I have a json that contains several users based on certain criteria. The number of users can vary, but I would like to create several buttons for each user returned that links to the users profile. the url is just '/profile/username'
format of json
[{"user":{"principal":"cat#sitter.com","schedule":null,"appointments":null,"roles":["ROLE_USER"],"attributes":{"principal":"cat#sitter.com","zipcode":"98077","firstname":"cat","password":"abc123","sitterFlag":"true","ownerFlag":"false","lastname":"sitter","username":"catsitter","preferredPet":"Cat"},"momento":"cat#sitter.com"},"password":"$2a$10$ltnL.mFqo7hatj69Ls76xeegjhEX0D4At9m1rlBHbQtDrV8MdSeAS","momento":"cat#sitter.com"},{"user":{"principal":"test#pets.com","schedule":null,"appointments":null,"roles":["ROLE_USER"],"attributes":{"principal":"test#pets.com","zipcode":"98077","firstname":"test","password":"abc123","sitterFlag":"false","ownerFlag":"false","lastname":"pets","username":"testpets"},"momento":"test#pets.com"},"password":"$2a$10$wDhS6Mb8syhC0YIqgVG2qu8J6lA.1T.UprMYwAX6O7Xb3YMhgX3bO","momento":"test#pets.com"},{"user":{"principal":"test#sitter.com","schedule":null,"appointments":null,"roles":["ROLE_USER"],"attributes":{"principal":"test#sitter.com","zipCode":"98077","firstname":"test","password":"abc123","lastname":"sitter","username":"testsitter"},"momento":"test#sitter.com"},"password":"$2a$10$DuIeWFSzhtAjX3lr8xBNiu2kV9kAJ/PQ6pB/EzkB7FkGWfRbwxkzy","momento":"test#sitter.com"},{"user":{"principal":"sit#sitter.com","schedule":null,"appointments":null,"roles":["ROLE_USER"],"attributes":{"principal":"sit#sitter.com","zipCode":"98077","firstname":"sit","password":"abc123","lastname":"sitter","username":"imasitter"},"momento":"sit#sitter.com"},"password":"$2a$10$2NKOQkGZO/jUer3UjNGzdugUhkMV1pJ1eT8NQjSPRto9/cRdm56sO","momento":"sit#sitter.com"},{"user":{"principal":"a#sitter.com","schedule":null,"appointments":null,"roles":["ROLE_USER"],"attributes":{"principal":"a#sitter.com","zipCode":"98077","firstname":"a","password":"abc123","lastname":"sitter","username":"asitter"},"momento":"a#sitter.com"},"password":"$2a$10$8x1uVqR28x5rwNrydieSyu1ILifBJ5n0dUsZI5tJ6MoUWMqXxrmeq","momento":"a#sitter.com"}]
I currently have it working if I hard code for each user:
<div className="container padded">
<div className="row">
<div className="col-6 offset-md-3">
<h2>Suggested Sitters</h2>
<button onClick={() => this.suggestSitter(this.props.user.principal)}>Click</button>
<hr/>
<div>
Sitters:
</div>
<Link to={this.setProfile(this.state.sitter ? this.state.sitter[1].user.attributes.username: ' ')} >
<button type="button">{this.state.sitter ? this.state.sitter[1].user.attributes.username: ' '}</button>
</Link>
</div>
</div>
</div>
the setProfile works like this:
setProfile(theUser) {
return '/profile/' + theUser;
}
Clicking a button will redirect to that user's profile page.
So basically, instead of hardcoding n buttons, I would like to dynamically create n buttons and each will link to '/profile/username/ for each user returned.
suggestSitter function:
suggestSitter(user){
var _this = this;
console.log('user', user);
axios.get('/api/user/suggest_sitter', { params: { principal: user } })
.then(function(response) {
console.log('Response: ' + JSON.stringify(response));
_this.setState({
sitter: response
});
})
.catch(function (e) {
console.log('Error: ' + e);
});
}
You can map the data to an array of Link (provide an unique key for it too):
{this.state.sitter.map((e) => (
<Link key={e.someUniqueProperty} to={this.setProfile(e.user.attributes.username)}>
<button type="button">{e.user.attributes.username}</button>
</Link>
))}
Suppose your data is:
const data = [
{user: {...}, attribute: {...}},
{user: {...}, attribute: {...}},
...
]
Now, you can follow these steps:
Create a stateless/stateful component(depending on your use case): UserButton or any other meaningful name:
const UserButton = () => (
<div className="container padded">
<div className="row">
<div className="col-6 offset-md-3">
/*...Add your remaining JSX....*/
</div>
</div>
</div>
)
Now in your parent component(from where you are actually rendering the data), you can do the following:
renderUserButtons = () => {
return data.map((userData) => (
<UserButton key="Some-unique-id-can-be-anything" PASS_YOUR_PROPS_HERE/>
))
}
render() {
return (
<div>
...
{this.renderUserButtons()}
...
</div>
);
}
Obviously, you don't need multiple components for this, but splitting it into smaller components looks good, easier to maintain and easier to test. Again it's my personal preference. You can use the convention whatever is best for you.
To create any UI component from some array, you can always use map function like below.
Array of JSON Object
let users = [{"name":"ABC"},{"name":"DEF"},{"name":"GHI"}];
Map Function
let userList = users.map((user,index)=>{return (<div>{index} - {user.name}<div>)})
this will give you following output:
0 - ABC
1 - DEF
2 - GHI
in map function user is the reference to one by one users from the array. Index is the key for each value from array (ex. 0,1,2....).
We are returning a JSX object from the return statement.
You can now use userList variable in render's return. Like below..
render(){ let userList = "...."; return(<div>{userList}</div>
I hope this would help.

Categories