I have a front-end react application posting data to a server. Using CKEditor and React Hook Form. When I console.log the data prior to posting I get the ideal html formatted text ( <p><strong> ). However, when I check the data I see html entities ( <p>...s<strong> ). I'd like the server to receive the data as I see it in the front end, as html formatted text, so I can show it properly in other parts of the app. Here's the relevant code.
CreateArticle.jsx
...
const [ckData, setCkData] = useState(null)
...
const onSubmit = data => {
// place tags into an array
modifyTag(data);
// retrive data from CKEditor, place into 'content'
modifyContent(data)
// 'content shows as html formatted text as intended
console.log(data)
// imported create article (POST) from axios.js
createArticle(data)
.then(res => {
const id = res.data.data.id;
setArticleId(id);
})
.catch(err => console.log(err.response.data.error))
}
...
const modifyContent = (data) => {
// React Hook Form troubles with CK and handleSubmit
// manually replace content with ckData
data.content = ckData
}
...
<Controller
as={<CKEditor
editor={ClassicEditor}
onBlur={(event, editor) => {
//save data to content variable
const content = editor.getData();
//save content to CkData hook
setCkData(content)
}}
/>}
name="content" control={control}
/>
...
Is there a front end solution to this?
Related
I was exploring Remix.run and making a sample app. I came across an issue that has been bothering me for some time now. Correct me if I am wrong: action() is for handling Form submission, and loader() is for fetching data initially.
For my application, I used mongoose to connect MongoDB, defined models, and defined querying function in a query.server.ts file. I want to fetch data from the database through a function defined in the query.server.ts file when an image is clicked on the UI. How can I do that without using forms? I cannot pre-fetch the data without knowing what image was clicked by the user.
You can create a resource route. These are like regular routes, but don't export a default component (no UI).
You can use the useFetcher hook and call fetcher.load() to call your resource route. The data is in fetcher.data.
// routes/query-data.ts
export const loader: LoaderFunction = async ({request}) => {
const url = new URL(request.url)
const img = url.searchParams.get('img')
const data = await getData(img)
return json(data)
}
// routes/route.tsx
export default function Route() {
const fetcher = useFetcher()
const handleImgClick = (e) => {
const img = e.target
fetcher.load(`/query-data?img=${img.attr('src')}`)
}
return (
<div>
<img onClick={handleImageClick} src="/images/file.jpg" />
<pre>{ JSON.stringify(fetcher.data, null, 2) }</pre>
</div>
)
}
I am working on an autocomplete app that I want users be able to make address search through the backend of Django but somehow the Api doesn't fetch data through the script, why is the payload not showing any data in the log console but rather an empty list?, I have tried calling the data from the browser as in example http://127.0.0.1:8000/search/?address=val , which fetches the json data response with a payload of data of addresses that match my search, but when i pass the url in my javescript it returns an empty data list with a 200 response. My experience in Js is mediocre, since I'm a novice.
<script>
new Autocomplete('#autocomplete',{
search : input => {
console.log(input)
const url = "/search/?address=${input}"
return new Promise(resolve => {
fetch(url)
.then( (response) => response.json())
.then( data => {
console.log(data)
resolve(data.data)
})
})
},
onSubmit : result => {
console.log(result)
window.open('/search/?address=${result}')
}
})
</script>
here is my search box Html
<h4>Seacrh for places</h4>
<div id="autocomplete" class="autocomplete">
<input class="autocomplete-input"/>
<ul class="autocomplete-result-list"></ul>
</div>
my view for search
def search_address(request):
address = request.GET.get('address')
playload = []
if address:
fake_address_objs = Address.objects.filter(address__icontains=address)
for fake_address_obj in fake_address_objs:
playload.append(fake_address_obj.address)
return JsonResponse({'status':200 , 'data': playload })
Returned empty data in the console log
Returned data in browser using http://127.0.0.1:8000/search/?address=v
Hi I'm new to Node/React, and I'm creating a learning project. It's platform that connects freelancers with nonprofit companies. Users (freelancers), view a list of companies, and click a button to connect to a company. Once this is clicked, the user will have that company added as a relationship in the database. This is working correctly.
Now I'd like users to visit a page and view their "connections", basically all the companies they connected with. In the database, I'm only storing the "companyHandle" in the association table. So currentUser.connections would give me an array of companyHandles ['aapl', 'gogl', 'msft']. So when the user views their connections, I would like to fetch data from the backend API, to retrieve more information about each company (companyName, numEmployees, etc..).
I tried to do that by looping through all the companyHandles, and fetching data from the API for each company, but I get the error React Hook "useEffect" may be executed more than once. Possibly because it is called in a loop...
What's a better way to do this? How can I fetch data for different companies? Below is my code (shortened)
schema
CREATE TABLE companies (
company_handle VARCHAR(25) PRIMARY KEY,
password TEXT NOT NULL,
company_name TEXT NOT NULL,
country TEXT NOT NULL,
num_employees INTEGER CHECK (num_employees > 0)
);
CREATE TABLE users (
username VARCHAR(25) PRIMARY KEY,
password TEXT NOT NULL,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT NOT NULL CHECK (position('#' IN email) > 1)
);
CREATE TABLE connections (
username VARCHAR(25)
REFERENCES users ON DELETE CASCADE,
company_handle VARCHAR(25)
REFERENCES companies ON DELETE CASCADE,
PRIMARY KEY (username, company_handle)
);
UserConnections.js
function UserConnections() {
const { currentUser } = useContext(UserContext);
const connections = currentUser.connections;
const [companies, setCompany] = useState([]);
if (connections) {
for (const connection in connections) {
useEffect(function getCompanyDetail() {
async function getCompany() {
setCompany(await VolunteerApi.getCurrentCompany(connection));
}
getCompany();
}, [connection]);
}
}
return (
<div>
{companies.length
? (
<div>
{companies.map(company => (
<CompanyCard
key={company.companyHandle}
companyHandle={company.companyHandle}
companyName={company.companyName}
country={company.country}
numEmployees={company.numEmployees}
/>
)
)}
</div>
) : (
<p>You have no connections</p>
)}
</div>
);
};
You can use promise.all to execute promises (api fetcher) and useEffect hook from React.
useEffect(() => {
setLoading(true); // If you want to add loader or spinner till companies info fetched
const connectionsPromises = connections.map((connection) => {
return VolunteerApi.getCurrentCompany(connection);
});
Promise.all(connectionsPromises).then((companies) => {
setCompany(companies); // save companies
setLoading(false); // disable loader
});
}, [connections])
Promise.all resolves promises parallelly
Basically, you can only use hooks at the top level of your component.
Take a look at the rules of hooks (including useEffect).
You should try to put your if and for loop inside the useEffect.
I am trying to request a PDF file from my java server through a react typescript app. Then trying to display this byte[] through react-pdf.
The request to the server looks like this:
const [invoice, setInvoice] = React.useState<any>()
const downloadPdf = (theInvoice: Invoice) => {
store.app.cubaRest?.invokeService<any>('billing_InvoiceService', 'generateInvoiceDocument', { invoice: theInvoice })
.then((response: any) => {
console.log(response)
let array= JSON.parse(response).content
setInvoice(array)
}).finally(()=>{
})
}
if (invoice) {
console.log("there is invoice")
return (
<div>
<Document
file={{ data: invoice }}
onLoadSuccess={onDocumentLoadSuccess}
onLoadError={console.error}
>
<Page pageNumber={pageNumber} />
</Document>
</div>
The console log from the raw "response" above looks like this:
{"report":{"_entityName":"report$Report","id":"1dd6746f-3580-6e3c-3aa6-e3f5db0a290b","code":"default-invoice","roles":[],"defaultTemplate":{"id":"0de287de-1931-a375-d10f-70ae431a3ca7","content":"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCEtLSBDcmVhdGVkIHdpdGggSmFzcGVyc29mdCBTdHVkaW8gdmVyc2lvbiA2LjE2LjAuZmluYWwgdXNpbmcgSmFzcGVyUmVwb3J0cyBMaWJyYXJ5IHZlcnNpb24gNi4xNi4wLTQ4NTc5ZDkwOWI3OTQzYjY0NjkwYzY1YzcxZTA3ZTBiODA5ODE5MjggIC0tPgo8amFzcGVyUmVwb3J0IHhtbG5zPSJodHRwOi8vamFzcGVycmVwb3J0cy5zb3VyY2Vmb3JnZS5uZXQvamFzcGVycmVwb3J0cyIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnNjaGVtYUxvY2F0aW9uPSJodHRwOi8vamFzcGVycmVwb3J0cy5z .......
When I set the state from the response the page just keeps rerendering and the pdf does not show. Presumably it is doing a re-render for every byte in the byte array.
Not sure how to resolve this. Also not sure if I am sending the byte[] correctly to setInvoice either. Or if the byteArray is in the correct format for that matter.
Was quite a simple solution.
instead of:
let array= JSON.parse(response).content
setInvoice(array)
do:
setInvoice({data: JSON.parse(response).content});
if (invoice) {
return (
<div>
<Document
file={invoice}
onLoadSuccess={onDocumentLoadSuccess}
onLoadError={console.error}
>
<Page pageNumber={pageNumber} />
</Document>
</div>
Heres the base64 approach
1. Given base64 string of the pdf file
const fileAsBase64 = || YOUR PDF FILE IN BASE64 AS STRING ||
2. Convert base64 string to bytearray
export const base64ToArrayBuffer = (base64) => {
const binaryString = window.atob(base64); // Comment this if not using base64
const bytes = new Uint8Array(binaryString.length);
return bytes.map((byte, i) => binaryString.charCodeAt(i));
}
3. Add the byearray to component by calling above function
<Document file={{ data :base64ToArrayBuffer(base64)}}/>
I'm working with draft-js for react where I make an api call (IN A FUNCTIONAL PARENT COMPONENT) and get contents to be put up in the editor. I have this code to insert the fetched data into the editor after receiving it in props:
Parent Component:
var draftContent = "";
var isContentFetched = false;
const CommentSection = () => {
let response = await fetch(url, {
method: "get",
headers: headers,
});
let query = await response.json(); // read response body and parse as JSON
draftContent = element.comment;
isContentFetched = true;
return(<RichTextEditor
isDraftFetched={isDraftFetched}
isContentFetched={isContentFetched}
placeholder=""
rows={6}
boxWidth="100%"
boxHeight="155px"
/>)
})
Editor Component:
componentDidUpdate(props) {
if(this.props.isContentFetched == true && draftAlreadyFilled== false) {
this._insertText(this.props.draftContent);
draftAlreadyFilled = true;
}
}
_insertText(htmlContent) {
this.setState({
editorState: EditorState.createWithContent(
ContentState.createFromBlockArray(
convertFromHTML(htmlContent)
)
),
})
}
Problem is, the text loaded and sent through props does not fill up in the editor. Instead once I am in the page and I click on refresh, then it loads fine.
PS: 1. I have checked related questions and those solutions did not work. 2. It is really necessary that I make the API call in the parent component.