I am trying to select a CSV file with some columns and data using file input. This is the content of the CSV
id,level,cvss,title,Vulnerability,Solution,reference, 963,LOW,7.8,Title - 963,Vulnerability - 963,Solution - 963,reference - 963, 964,CRITICAL,4.6,Title - 964,Vulnerability - 964,Solution - 964,reference - 964, 965,INFO,0,Title - 965,Vulnerability - 965,Solution - 965,reference - 965, 966,CRITICAL,10,Title - 966,Vulnerability - 966,Solution - 966,reference - 966, 967,HIGH,7.5,Title - 967,Vulnerability - 967,Solution - 967,reference - 967, 968,HIGH,5,Title - 968,Vulnerability - 968,Solution - 968,reference - 968, 969,MEDIUM,7.5,Title - 969,Vulnerability - 969,Solution - 969,reference - 969,
This is the code for the UI
import { Form } from "@remix-run/react";
import type { ActionArgs, UploadHandler } from "@remix-run/server-runtime";
import {
composeUploadHandlers,
parseMultipartFormData,
} from "@remix-run/server-runtime/dist/formData";
import { createMemoryUploadHandler } from "@remix-run/server-runtime/dist/upload/memoryUploadHandler";
import { csvUploadHandler } from "~/models/code.server";
export async function action({ request, params }: ActionArgs) {
const uploadHandler: UploadHandler = composeUploadHandlers(
csvUploadHandler,
createMemoryUploadHandler()
);
const formData = await parseMultipartFormData(request, uploadHandler);
const selected_csv = formData.get("selected_csv");
console.log("========== selected csv file: ", selected_csv);
return selected_csv;
}
export default function codeListImport() {
return (
<div style={{ textAlign: "center" }}>
<h1 style={{ marginBottom: 10 }}>UPDATE CODE LIST</h1>
<Form method="post" encType="multipart/form-data">
<input
type="file"
accept=".csv"
name="selected_csv"
/>
<button type="submit" className="btn btn-sm">
UPLOAD CSV
</button>
</Form>
</div>
);
}
This is the code.server.ts file
export const csvUploadHandler: UploadHandler = async ({
name,
filename,
data,
contentType,
}) => {
if (name !== "selected_csv") {
return undefined;
}
console.log("===== file name", filename);
console.log("===== data", data);
console.log("===== content type", contentType);
};
I was trying to get the content of the CSV file using data
given by the uploadHandler
. I get the correct name of the HTML input element, file name as well as the content type. But when I console log data
it shows me this on the log:
What I clearly do not get is how to decode this object
I have gone through multiple tutorials and many stackoverflow posts but I am still having a hard time understanding what exactly is the Symbol.asyncIterator
. I am a newbie for ES6. Please help me on this matter
In your UploadHandler
, the parameter is type UploadHandlerPart
export type UploadHandlerPart = {
name: string;
filename?: string;
contentType: string;
data: AsyncIterable<Uint8Array>;
};
So data
is not the CSV string, it's an AsyncIterable
of bytes. You need to convert this to a string and then return that from your handler.
export const csvUploadHandler: UploadHandler = async ({
name,
filename,
data,
contentType,
}) => {
if (name !== 'selected_csv') {
return undefined;
}
// get data in chunks
let chunks = [];
for await (let chunk of data) {
chunks.push(chunk);
}
// convert chunks to string using Blob()
return await new Blob(chunks, { type: contentType }).text();
};
I have an example here: https://stackblitz.com/edit/node-ubpgp5?file=app%2Froutes%2Findex.tsx
Since you're not really doing anything in your csvUploadHandler
, you can simply use the existing memoryUploadHandler(). Your csv file will be in formData
as a File
type.
const uploadHandler = createMemoryUploadHandler();
const formData = await parseMultipartFormData(request, uploadHandler);
const csvFile = formData.get('selected_csv') as File;
const csv = await csvFile.text();