React Dropzone Component - How to dynamically change postUrl? - javascript

I am using react dropzone component https://github.com/felixrieseberg/React-Dropzone-Component to facilitate the dragging and dropping of files onto a site.
I want each file that gets dropped onto the dropzone to get posted to a different url (AWS Pre-Signed URL). Essentially I want the the component config parameter 'postUrl' to dynamically change as this pre-signed URL changes.
I currently have the following component configuration set
class Uploader extends React.Component {
constructor(props){
super(props);
this.dropzone = 'null'
}
config = () => (
{
iconFiletypes: ['.jpg', '.png', '.gif'],
showFiletypeIcon: true,
postUrl: this.dropzone.options.url || 'no-url'
}
);
eventHandlers = () => (
{
processing: function(file) {
},
init: dz => this.dropzone = dz,
}
);
djsConfig = (requestID=this.props.requestId) => (
{
addRemoveLinks: false,
acceptedFiles: "image/jpeg,image/png,image/gif",
autoProcessQueue: true,
init: function () {
this.on("processing", async (file) => {
const presigned_url = await uploadUrl(file, requestID, () => {})
this.options.url = presigned_url;
});
}
}
);
}
I get the following error when I load the page/component:
Uncaught TypeError: Cannot read property 'url' of undefined
Updating the options.url on the Dropzone object via djsConfig when a file is processed doesn't get the chance to update the postUrl: this.dropzone.options.url as I would like?

As commented by lex.
Change your init method as below:
init:function () {
var _this=this;
this.on("processing", async (file) => {
const presigned_url = await uploadUrl(file, requestID, () => {})
_this.options.url = presigned_url;
});
}

Related

Can't click buttons in the title bar (Electron App)

I try to build a simple Text Editor using Electron.
At the moment I want to add a custom title bar which doesn't really work as the buttons are not clickable...
I added an onclick tag to the buttons.
main.js:
//-- variables --\\
const { BrowserWindow, app, Menu, dialog, ipcMain } = require("electron")
let window
let filePath = null //currently opened file
let openFiles = [] //opened files
//-- startup --\\
app.whenReady().then(function()
{
createWindow()
createMenu()
})
//-- functions --\\
function createWindow()
{
window = new BrowserWindow
({
width: 1000,
height: 600,
frame: false,
icon: "./assets/icon.png",
darkTheme: true,
autoHideMenuBar: true,
webPreferences:
{
nodeIntegration: true,
contextIsolation: false
}
})
//window.maximize()
window.loadFile("./frontend/index.html")
window.webContents.openDevTools()
}
function createMenu()
{
Menu.setApplicationMenu(Menu.buildFromTemplate
([
{
label: "File",
submenu:
[
{
label: "Save",
click: saveFile,
accelerator: "CmdOrCtrl+S"
},
{
label: "Open",
click: openFile,
accelerator: "CmdOrCtrl+O"
},
{
label: "New",
click: newFile,
accelerator: "CmdOrCtrl+N"
}
]
}
]))
}
async function promptFilePathOpen()
{
await dialog.showOpenDialog
({ properties: ["openFile"] }).then(function(res)
{
if(res.canceled) return
filePath = res.filePaths[0]
})
}
async function promptFilePathSave()
{
await dialog.showSaveDialog().then(function(res)
{
if(res.canceled) return
filePath = res.filePath
})
}
async function openFile()
{
await promptFilePathOpen()
//openFiles.push(filePath)
window.webContents.send("crd-openFile", filePath)
}
async function saveFile()
{
if(filePath == null || undefined) await promptFilePathSave()
window.webContents.send("crd-saveFile", filePath)
}
async function newFile()
{
filePath = null
await promptFilePathSave()
window.webContents.send("crd-resetEditor")
window.webContents.send("crd-saveFile", filePath)
}
//-- listeners --\\
app.on("window-all-closed", function()
{
if(process.platform != "darwin") app.quit()
})
ipcMain.on("crd-minimizeWindow", function() //does not get called by the renderer
{
//coming soon
})
ipcMain.on("crd-toggleWindowSize", function() //does not get called by the renderer
{
//coming soon
})
ipcMain.on("crd-closeWindow", function() //does not get called by the renderer
{
console.log("quit")
})
renderer/script.js:
//-- imports --\\
const { ipcRenderer } = require("electron")
const fs = require("fs")
const editorElem = document.querySelector("textarea.editor")
//-- functions --\\
function minimizeWindow() // does not get called by the button (index.html)
{
ipcRenderer.send("crd-minimizeWindow")
}
function toggleWindowSize() // does not get called by the button (index.html)
{
ipcRenderer.send("crd-toggleWindowSize")
}
function closeWindow() // does not get called by the button (index.html)
{
ipcRenderer.send("crd-closeWindow")
}
//-- listeners --\\
ipcRenderer.on("crd-openFile", function(e, path)
{
editorElem.value = fs.readFileSync(path, "utf-8")
})
ipcRenderer.on("crd-saveFile", function(e, path)
{
fs.writeFile(path, editorElem.value , function(res, err)
{
if(err) throw err
})
})
ipcRenderer.on("crd-resetEditor", function()
{
editorElem.value = ""
})
The entire code is avalable on my GitHub, because I do not want the whole question consisting of code :)
Two issues here:
You defined functions like closeWindow, but you didn't actually add an event listener for them. You mention onclick but I can't see that in your code. So the first step would be to add document.querySelector('.closeWindow').addEventListener('click', closeWindow) .
You made the whole title bar draggable, including the buttons. That means that the role of the buttons is also a draggable area, so when you click them, you start the drag operation instead of sending a click event. The solution is therefore to make sure the button area does not have the -webkit-app-region: drag style but only the area left to them has. This will probably require you to redesign the HTML layout for the title bar a bit, since this won't work well with the whole thing being a grid.
For more details, see this tutorial.

Component does not re-render after changes done by event listener in constructor [duplicate]

Actually this code is from ionic, and I am processing an image that I get through the photo capture. everything works fine, I get the blob, but for some reason my image is not shown in the template, I think the angular binding is not updating. What can I do to force it?
myblob:any=null;
takePhoto() {
const options: CameraOptions = {
quality: 60,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
allowEdit: true,
};
this.camera.getPicture(options).then(
(imageData) => {
this.file
.resolveLocalFilesystemUrl(imageData)
.then((entry: FileEntry) => {
entry.file((file) => {
this.readFile(file);
});
});
},
(err) => {
// Handle error
}
);
}
readFile(file: any) {
const reader = new FileReader();
reader.onloadend = () => {
const imgBlob = new Blob([reader.result], {
type: file.type,
});
//my ngModel (updating) ****------------->
this.myblob = URL.createObjectURL(imgBlob);
console.log(this.documento_reverso);
};
reader.readAsArrayBuffer(file);
}
In my template:
<button (click)="takePhoto()">Take photo</button>
<img *ngIf="myblob" [src]="myblob"> --> is not show at first time button click
how can do it?
When I click the button and get the photo, the image is not displayed, but the second time I click the button it is immediately displayed.
You can wrap the code in NgZone.run to make sure that it runs in the Angular zone and that the change is picked up by change detection:
import { NgZone } from '#angular/core';
constructor(private ngZone: NgZone) { }
readFile(file: any) {
...
this.ngZone.run(() => {
this.myblob = URL.createObjectURL(imgBlob);
});
...
}

Reset FilePond Input in Javascript

I have implemented Filepond uploaded in my page. When the user selects a file, I set that file on a html canvas for edits. However when the user wants to upload another file, filepond input retains last uploaded file.
I have tried FilePond.destroy(inputElement); after the file is successfully set on the canvas in the FilePond:addfile event.
$('.upload-file').filepond();
$.fn.filepond.registerPlugin(
FilePondPluginFileValidateType,
FilePondPluginFileValidateSize,
FilePondPluginImageResize,
FilePondPluginImageExifOrientation,
FilePondPluginImagePreview,
FilePondPluginImageTransform,
FilePondPluginImageCrop,
FilePondPluginImageValidateSize,
);
FilePond.setOptions({
labelIdle: 'Drag & Drop your file or <span class="filepond--label-
action"> Browse </span>',
maxFiles: 1,
allowDrop: true,
allowMultiple: false,
dropOnPage: true, //for page to work, element has to be false https://github.com/pqina/filepond/issues/113
dropOnElement: false,
labelTapToCancel: '', //we dont want to allow cancel
labelTapToUndo: '',
maxFileSize: intFileSizeInMB,
allowReplace: true,
allowRevert: false,
instantUpload: false
});
const pond = document.querySelector('.filepond--root');
pond.addEventListener('FilePond:addfile', e => {
console.log('File added', e.detail);
if (e.detail) {
if (e.detail.file && e.detail.file.file.name) {
SetFileOnCanvas(e.detail.file.file, e.detail.file.file.name);
const inputElement = document.querySelector('input[type="file"]');
FilePond.destroy(inputElement);
}
}
});
pond.addEventListener('FilePond:processfile', e => {
console.log('Process File COMPLETE', e.detail);
});
After a file is uploaded and set to Canvas the file upload input should be cleared and ready for another upload.
Working solution
var pond_ids = [];
if (pond.getFiles().length != 0) { // "pond" is an object, created by FilePond.create
pond.getFiles().forEach(function(file) {
pond_ids.push(file.id);
});
}
pond.removeFiles(pond_ids);
After upload file "Complete function"
you can do like this (simple example):
if (filePond.getFiles().length != 0) {
for (var i = 0; i <= filePond.getFiles().length - 1; i++) {
filePond.removeFile(filePond.getFiles()[0].id)
}
}
I know its too late but you can use
let filePond = FilePond.find(document.getElementById(filePondElementId));
if (filePond != null) {
//this will remove all files
filePond.removeFiles();
}
<script src="https://unpkg.com/filepond/dist/filepond.min.js"></script>
Assuming that you create your filepond instance through function create_pondProfile and your input has class filepond, in you filepond config in server block do like this:
server: {
url: '',
process: {
url: '/path/to/upload/',
headers: {'X-CSRF-TOKEN': csrf},
ondata: (formData) => {
return formData;
},
onload: (response) => {
FilePond.destroy(document.querySelector('.filepond'));
create_pondProfile('.filepond');
}
},
...
...
}
It will destroy current instance of filepond and creates new one after upload.

Accesing the data from an input button for Vue

I installed the Vuetify upload button with npm (https://www.npmjs.com/package/vuetify-upload-button).
However there is little documentation on it and I am not sure how to read the data that is selected when the input button is used.
HTML(part):
<upload-btn title="select" name="pinimage">test</upload-btn>
<v-btn
:disabled="!valid"
#click="submit"
>
submit
</v-btn>
JS:
(See the submit function where I try to log the selected data)
<script>
import { mapState } from 'vuex';
import UploadButton from 'vuetify-upload-button';
export default {
name: "addinspiration",
components: {
'upload-btn': UploadButton
},
computed: {
...mapState([
'backenderror'
])
},
data: () => ({
backenderror: '',
valid: true,
email: '',
pinimage: '',
}),
methods: {
submit () {
console.log(this.pinimage.files);
this.$store.dispatch('AddInspiration', {
pinimage: this.pinimage.files,
});
},
clear () {
this.$refs.form.reset()
}
},
}
If I don't misunderstood your question then you could also try like this.
According to its documentation, fileChangedCallback is a callback for when a file is selected, returns a File object and its default value is undefined.
Thus, you could use FileReader() to read the data of the file.
HTML
<upload-btn :fileChangedCallback="getFile"></upload-btn>
JS
data() {
return {
myFile: ''
}
},
methods: {
getFile (file) {
let vm = this
let reader = new FileReader()
reader.onload = e => {
vm.myFile = e.target.result
}
reader.readAsDataURL(file)
}
}

React js Stripe checkout is not working

I am trying to render a stripe checkout default form in React js application.
<form action="/your-server-side-code" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" className="stripe-button"
data-key="pk_test_oDALA0jNyxDzbRz5RstV4qOr"
data-amount="999"
data-name="test"
data-description="Widget"
data-image="https://stripe.com/img/documentation/checkout/marketplace.png"
data-locale="auto">
</script>
</form>
Its not displaying anything and not getting error also.
How do i get that pay button and form.
The main issue you are probably having is loading a script within React.
One approach is to load the checkout script only when needed (assuming some form of spa), then just directly call it. This is akin to the "custom" version on the documentation page: https://stripe.com/docs/checkout#integration-custom
If you are already loading checkout.js (for example before your "app.js"), then the below can be simplified a bit by not manually loading in the script.
import React from 'react';
export default class Cards extends React.Component {
constructor(props:Object) {
super(props);
this.state = {
loading: true,
stripeLoading: true,
};
}
loadStripe(onload:Function) {
if(! window.StripeCheckout) {
const script = document.createElement('script');
script.onload = function () {
console.info("Stripe script loaded");
onload();
};
script.src = 'https://checkout.stripe.com/checkout.js';
document.head.appendChild(script);
} else {
onload();
}
}
componentDidMount() {
this.loadStripe(() => {
this.stripehandler = window.StripeCheckout.configure({
key: 'pk_test_xxxxxxxxxxxxxxxxxxxxxxxx',
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: (token) => {
this.setState({ loading: true });
axios.post('/your-server-side-code', {
stripeToken: token.id,
});
}
});
this.setState({
stripeLoading: false
});
});
}
componentWillUnmount() {
if(this.stripehandler) {
this.stripehandler.close();
}
}
onStripeUpdate(e:Object) {
this.stripehandler.open({
name: 'test',
description: 'widget',
panelLabel: 'Update Credit Card',
allowRememberMe: false,
});
e.preventDefault();
}
render() {
const { stripeLoading, loading } = this.state;
return (
<div>
{(loading || stripeLoading)
? <p>loading..</p>
: <button onClick={this.onStripeUpdate}>Add CC</button>
}
</div>
);
}
}
Chris's answer was excellent, however I had to make a few minor changes in order for the code to function. I've also removed the TypeScript function types (for those of us not using TypeScript). Comments are added where changes to the answer have been made. FYI this is my first post, please let me know if this should be a Comment instead of an Answer.
export default class Cards extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
stripeLoading: true,
};
// onStripeUpdate must be bound or else clicking on button will produce error.
this.onStripeUpdate = this.onStripeUpdate.bind(this);
// binding loadStripe as a best practice, not doing so does not seem to cause error.
this.loadStripe = this.loadStripe.bind(this);
}
loadStripe(onload) {
if(! window.StripeCheckout) {
const script = document.createElement('script');
script.onload = function () {
console.info("Stripe script loaded");
onload();
};
script.src = 'https://checkout.stripe.com/checkout.js';
document.head.appendChild(script);
} else {
onload();
}
}
componentDidMount() {
this.loadStripe(() => {
this.stripeHandler = window.StripeCheckout.configure({
key: 'pk_test_xxxxxxxxxxxxxxxxxxxxxxxx',
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: (token) => {
this.setState({ loading: true });
// use fetch or some other AJAX library here if you dont want to use axios
axios.post('/your-server-side-code', {
stripeToken: token.id,
});
}
});
this.setState({
stripeLoading: false,
// loading needs to be explicitly set false so component will render in 'loaded' state.
loading: false,
});
});
}
componentWillUnmount() {
if(this.stripeHandler) {
this.stripeHandler.close();
}
}
onStripeUpdate(e) {
this.stripeHandler.open({
name: 'test',
description: 'widget',
panelLabel: 'Update Credit Card',
allowRememberMe: false,
});
e.preventDefault();
}
render() {
const { stripeLoading, loading } = this.state;
return (
<div>
{(loading || stripeLoading)
? <p>loading..</p>
: <button onClick={this.onStripeUpdate}>Add CC</button>
}
</div>
);
}
}

Categories

Resources