Skip to main content

com.sabre.redapp.example3.web.file.reader Sample

As a Red App developer, you are able to add define button to open local file system from the application and upload file for handling data from it. There is also possibility to create Drag-and-Drop File Uploader. Both features work on web and desktop.

Sample was developed with use of Web React Modal Sample, so it is worth being familiar with it.

This sample defines the following typings for both the state and props of a component.

interface Props {
    file: File | null
}

interface UpdateProps {
    updateFile: (File) => void
}

interface OwnState {
    dragging: boolean;
    previousDragEvent: string;
}

File Upload Button

To create a button for uploading files, you need to add an html 'input' component with 'type' property set to 'file' and 'onChange' property set to the method that will handle pressing the button.

<form>
    <input
        className="importFilesInput"
        type='file'
        onChange={e => this.uploadFile(e)}
    >
    </input>
</form>

In our sample 'uploadFile' method updates file inside props and additionally unblock button which is used to read data from uploaded file.

uploadFile(event): void {
    this.props.updateFile(event.target.files[0]);
    $('#readDataButton').removeClass('disabled');
}

You also have the option to create your own component, which will act as file input after performing the action.

selectFile(): void {
    $('.importFilesInput').click();
};

<Button
    key={1}
    className="btn-success selectButton"
    onClick={this.selectFile}
>
    Select File
</Button>

To hide original file input you may use CSS.

Drag-and-Drop File Uploader

To create a field that supports Drag-and-Drop File uploading, you have to use the DragAndDropComponent component from sabre-ngv-UIComponents/dragAndDropFileInput/DragAndDropComponent SDK module.

This component does not take any parameters, it is just the body which contains the obligatory dependencies for the proper works of the drag-and-drop functionality. Inside this component you need to put code defining support for drag-and-drop functionality.

<DragAndDropComponent>
    <div
        className={dragAndDropClass}
        onDragStart={e => this.onDragEvent(e)}
        onDragEnter={e => this.onDragEvent(e)}
        onDragOver={e => this.onDragEvent(e)}
        onDragLeave={e => this.onDragEvent(e)}
        onDrop={e => this.onDragEvent(e)}
    >
        <div className="contents">
            <span className="fileName">{fileName}</span>
            <br/>
            <span>Drag & Drop File</span>
        </div>
    </div>
</DragAndDropComponent>

Keep in mind that you need to define handling of 'DragEvent' methods.

onDragEvent(event: DragEvent<HTMLDivElement>): void {
    event.preventDefault();
    event.stopPropagation();

    if (event.type === 'drop') {
        const files: FileList = event.dataTransfer && event.dataTransfer.files;
        if (files && files.length) {
            this.setState({
                dragging: false
            });
            this.props.updateFile(files[0]);
            $('#readDataButton').removeClass('disabled');
        }
    } else if (event.type === 'dragenter' && event.dataTransfer.items && event.dataTransfer.items[0]) {
        this.setState({
            dragging: true
        });
    } else if (event.type === 'dragleave' && this.state.previousDragEvent == 'dragover') {
        this.setState({
            dragging: false
        });
    }
    this.setState({
        previousDragEvent: event.type
    });
}

A 'drop' event is used to handle dropping files into the designated area.

The other events are used to visualize the dragging action.

Use data from the file

In the above example the files were saved to the props, which allows to use them freely.

An example component that reads text from file given in props.

interface Props {
    file: File | null;
}

interface OwnState {
    fileName: string,
    fileText: string
}

class ModalComponentPure extends React.Component<Props, OwnState> {

    constructor(props) {
        super(props);

        this.state = {
            fileName: this.props.file.name,
            fileText: ""
        };

        const reader = new FileReader()
        reader.onload = async (e) => {
            const text = (e.target.result);
            this.setState({
                fileText: text.toString()
            });
        };
        reader.readAsText(this.props.file);
    }

    render(): JSX.Element {

        return (
            <div>
                <div className="readFileName">
                    <p>{this.state.fileName}</p>
                </div>
                <div className="readFileText">
                    <p>{this.state.fileText}</p>
                </div>
            </div>
        );
    }
}

function mapStateToProps(state: StoreData): Props {
    return {
        file: state.file
    };
}

export const ReadDataModal = connect<Props, {}, {}>(mapStateToProps)(ModalComponentPure);

On the current version of embedded jxbrowser (7.14.13) this feature does not work on macOS desktop client. Users that use it will have to use standard file select input.