I created a html component:

and a select file input component.
When I select a file from browser, will call query below:
let currentDocument = null;
const container = document.querySelector("#document-container");
currentDocument = fileButton1.files[0];
if (!currentDocument)
return;
console.log(fileButton1.files[0]);
docx.renderAsync(currentDocument, container);
When I run. The console raise error:
I think the reason is because the file has been encoded in bas64.
How can I decoded file?
Tess
2
Hi @Hung_Phan
It looks like you're using the .files
property, which doesn't have base64 (the base64 value is in the .value
property):

When working with base64 in Retool, you can use atob() to decode it
Tess
3
Are you using an external library? If so, can you share the link?
I'm thinking this script/html may need to be handled within a custom component
Hello, you should use custom component which support js.
Here is my basic demo for your reference.
the code in Iframe Code
<style>
@import url('https://rsms.me/inter/inter.css');
html { font-family: 'Inter', sans-serif; }
@supports (font-variation-settings: normal) {
html { font-family: 'Inter var', sans-serif; }
}
* {
font-family: 'Inter', sans-serif;
}
body {
margin: 0;
}
#react {
height: 100%;
width: 100%;
}
.card {
min-width: 0;
min-height: 120px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 12px 24px;
border-radius: 4px;
border: 1px solid #cccccc;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
background-color: #ffffff;
}
.title-container {
display: flex;
justify-content: space-between;
align-items: center;
line-height: 24px;
}
.title {
font-size: 18px;
font-weight: 700;
text-overflow: ellipsis;
white-space: nowrap;
}
.docs-link {
font-size: 12px;
font-weight: 500;
color: #b062bc;
text-decoration: none;
}
.docs-link:hover {
color: #9846a4;
}
.content {
margin-top: 4px;
font-size: 12px;
line-height: 18px;
font-weight: 400;
color: #777777;
}
.button-container {
display: flex;
align-items: center;
gap: 8px;
margin-top: 12px;
}
.button {
border: none;
border-radius: 4px;
padding: 8px 16px;
font-weight: 500;
font-size: 12px;
cursor: pointer;
outline: none;
appearance: none;
user-select: auto;
}
.button--main {
background-color: #b062bc;
color: #ffffff;
}
.button--main:hover {
background-color: #9846a4;
}
.button--secondary {
color: #b062bc;
background-color: white;
border: 1px solid #b062bc;
}
.button--secondary:hover {
color: #9846a4;
border: 1px solid #9846a4;
}
</style>
<!-- You can add any HTML/CSS/JS here. UMD versions are required.
Keep in mind that Custom Components are sensitive to bundle sizes, so try using a
custom implementation when possible. -->
<script crossorigin src="https://unpkg.com/core-js-bundle@3.3.2/minified.js"></script>
<script crossorigin src="https://unpkg.com/jszip/dist/jszip.min.js"></script>
<script crossorigin src="https://volodymyrbaydalka.github.io/docxjs/dist/docx-preview.js"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="react"></div>
<script type="text/babel">
const MyCustomComponent = ({ triggerQuery, model, modelUpdate }) => (
<div className="card">
<div className="title-container">
<div className="title">Custom component</div>
<a href="https://docs.retool.com/docs/custom-components" className="docs-link">View docs</a>
</div>
<div className="content">
{/* The text below is dynamic and specified by the model. */}
{model.displayText}
</div>
<div className="button-container">
{/* This button fires a dynamic query (specified in the model) when clicked. */}
<button
className="button button--main"
onClick={() => triggerQuery(model.queryToTrigger)}
>
Trigger query
</button>
<input type="file" id="files" onChange={()=>aa()}/>
<div id="document-container" className="overflow-auto flex-grow-1 h-100"></div>
{/* This button updates the model when clicked. */}
<button
className="button button--secondary"
onClick={() => modelUpdate({ displayText: 'The body of this text references "model.displayText", which just changed!' })}
>
Update model
</button>
</div>
</div>
)
function aa(){
console.log(docx)
let currentDocument = null;
const docxOptions = Object.assign(docx.defaultOptions, {
debug: true,
experimental: true
});
const container = document.querySelector("#document-container");
const fileInput = document.querySelector("#files");
currentDocument = fileInput.files[0];
if (!currentDocument)
return;
docx.renderAsync(currentDocument, container, null, docxOptions)
.then((x) => {
});
};
// This is the entrypoint for the React component.
const ConnectedComponent = Retool.connectReactComponent(MyCustomComponent)
const container = document.getElementById('react')
const root = ReactDOM.createRoot(container)
root.render(<ConnectedComponent />)
</script>
Attached pls find app json, you can check it
docx.json (70.6 KB)
by import it to your new create app.
1 Like
I try use atob() for decode value, it working on file csv. Do not working on docx file.
Yes, the same libs I use.
It work on my side.
Are you on retool cloud? Have got error message in debug?
1 Like