This is a electron +vue3 + vite project.
Now I can drag the folder here and get nothing
I want to get the file that I dragged in.
electron: 23.0.0
vue: 3.2.0
<template>
<div class="split-view">
<div class="split-view-main">
<div class="split-view-main-content">
<div
class="pane"
ref="pane"
#drop.stop.prevent="handleDrop"
#dragover="handleDragover"
#dragenter="handleDragover"
>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { isFolder } from '#/utils/file'
function handleDrop(e: DragEvent) {
e.stopPropagation()
e.preventDefault()
let { items } = e.dataTransfer!
console.log('items--->', e, items)
if (items && items[0].webkitGetAsEntry() !== null) {
isFolder(items)
}
}
function handleDragover(e: any) {
e.stopPropagation()
e.preventDefault()
e.dataTransfer.dropEffect = 'copy'
}
</script>
This is the drag event from the console:
Related
So im building a nuxt application, and I want to the Page to scroll down to a specific element, after I clicked a button.
The button and the element are in two different components, but on the same Page.
So I read that this is a problem in Nuxt.js and you have to create a specific file to make it work.
I created the folder called app and in app I created the file router.scrollBehavior.js the code of the file it the following
export default async function (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
}
const findEl = (hash, x) => {
return document.querySelector(hash) ||
new Promise((resolve, reject) => {
if (x > 50) {
return resolve()
}
setTimeout(() => { resolve(findEl(hash, ++x || 1)) }, 100)
})
}
if (to.hash) {
const el = await findEl(to.hash)
if ('scrollBehavior' in document.documentElement.style) {
return window.scrollTo({ top: el.offsetTop, behavior: 'smooth' })
} else {
return window.scrollTo(0, el.offsetTop)
}
}
return { x: 0, y: 0 }
}
My button is in the hero file, i created a click function called goto()
<template>
<section class="hero-section">
<div class="left">
<header id="hero-text" class="hero-header">
<h1 #click="goto()">Web Development <br> Web Design</h1>
<p>Hi, ich bin Alex. Ich designe und programmiere moderne, kreative und schnelle Webseiten. Umgesetzt mit den neusten Technologien.</p>
</header>
<UiButtonApp
id="hero-btn"
text="Schau dir meine Arbeit an!"
/>
</div>
<div class="right">
<img id="hero-img" src="~/assets/img/hero-img.jpg" alt="hero-img">
<div id="hero-object"></div>
<img class="dots" id="hero-dots" src="~/assets/img/dots.png" alt="logo">
</div>
</section>
</template>
<script>
import { gsap } from "gsap";
export default {
data(){
return{
}
},
methods: {
goto() {
//what code to put here
}
}
}
How can I now call the function? And make it work?
If you want to use router.scrollBehavior.js. Set a router action and send it to a especific hash:
methods: {
goto() {
this.$router.replace({ name: this.$route.name, hash: '#example' });
}
}
Don`t forget to set id in the component to go.
<div id="example">
</div>
I am working on React JS app, where I am trying to upload files to Firebase. I can easily upload the files and even a single file but the problem is when I am trying to show the progress of the file uploaded on individual file. I have built a UI, when a user selects files, the files get rendered and shows the file size, name and type etc. When I click the upload button, the upload get started in the background. What I am trying to do is, how can I show the progress of multiple files on the View.
The State
this.state = {
selectedFilesPrev: [],
filesPreviewAble: false,
multiple: true,
showLoaders: false
}
The JSX DOM
render() {
if(!this.state.filesPreviewAble){
return (
<div className='container'>
<div className='file-uploader-page' >
<div className='upload-icon'> <img src={uploadIcon} alt='upload'/> </div>
<p> Drag and Drop Files </p>
<p className='orSeparate'>Or</p>
<div className='files-upload-btn'>
<input type='file' id='file-upload' multiple={this.state.multiple} onChange={this.buttonUpload}/>
<label htmlFor='file-upload' className='rcaBtn'> Upload Files </label>
</div>
</div>
</div>
)
} else if(this.state.filesPreviewAble){
let l = '';
if(this.state.showLoaders){
l = <div className='file-uploading-bar'> <div className='fub-uploaded' style={{width:`${this.state.selectedFilesPrev.progress.percent}%`}}></div> </div>
} else { l = ''}
return (
<div className='container'>
<div className='files-preview container-fluid' >
<div className='fp-head'> Files to be Uploaded </div>
<div className='fp-files'>
{
this.state.selectedFilesPrev.map( (e, i) => {
return (
<div className='single-file row' key={i}>
<div className='file-preview col-2'>
<img src={e.img} alt='icon' />
</div>
<div className='file-meta col-9'>
<span className='file-name'> {e.meta.name} </span>
<span className='file-size'> {this.formatFileSize(e.meta.size)} - {e.meta.type} </span>
</div>
<div className='file-close col-1'> <span onClick={this.removeFile}>×</span> </div>
{l}
</div>
)
})
}
</div>
<div className='fp-upload'>
<button className='rcaBtn' onClick={this.handleUploadingFiles}>Upload Now</button>
</div>
</div>
</div>
)
}
}
The Files Selector Code
buttonUpload(event){
let object = event.target.files;
let files = []
for (const key in object) {
if (object.hasOwnProperty(key)) {
const element = object[key];
files.push(element)
}
}
let i = 0;
files.map( f => {
this.generatePreviewData(f, (prev) => {
i++;
this.state.selectedFilesPrev.push({
meta : f,
img : prev,
progress : {
percent : 0,
upoaded : false
}
})
if(i === files.length){
this.setState({
filesPreviewAble : true
})
}
})
return 0;
})
}
The Uploader Function (Which Works Perfect)
handleUploadingFiles(){
console.log(this.state.selectedFilesPrev)
this.setState({ showLoaders : true })
this.state.selectedFilesPrev.map( (file, idx) => {
let task = stdb.ref(`Images/${file.meta.name}`).put(file.meta);
task.on('state_changed', snapshot => {
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
this.state.selectedFilesPrev[idx].progress.percent = progress;
console.log("FILE # "+idx,' Upload is ' + progress + '% done');
},
error => {
console.log(error)
},
() => {
stdb.ref('Images').child(file.meta.name).getDownloadURL().then( url => {
console.log(url)
})
})
})
}
Note : What I want is simply, when the user click the upload button, each and every file uploading progress should be shown on the UI. The handleUploadingFiles() have the progress, which outputs the progress for each task, but I am unable to show that progress on the component.
In my webApp project, I want to click a letter, and the relative content will be scrolled to display.
Here is js code:
<script>
import Bscroll from 'better-scroll'
export default {
name: 'CityList',
props: {
cities: Object,
hotCities: Array,
letter: String
},
watch: {
letter () {
if (this.letter) {
const element = this.$refs[this.letter][0]
this.scroll.scrollToElement(element)
}
}
},
mounted () {
this.scroll = new Bscroll(this.$refs.wrapper)
}
}
</script>
I used vue 2.9.3
But I got a error:
[Vue warn]: Error in callback for watcher "letter": "TypeError: Cannot read property '0' of undefined"
who can help me?
<div
class="area"
v-for="(item, key) of cities"
:key="key"
>
<div class="title border-topbottom">{{key}}</div>
<div class="item-list">
<div
class="item border-bottom"
v-for="innerItem of item"
:key="innerItem.id"
>
{{innerItem.name}}
</div>
</div>
</div>
I should add :ref="key"
<div
class="area"
v-for="(item, key) of cities"
:key="key"
:ref="key"
>
I think there is a time when watch function run, this.$refs[this.letter] is not available yet. So you might want to check:
watch: {
letter () {
if (this.letter && this.$refs[this.letter]) {
const element = this.$refs[this.letter][0]
this.scroll.scrollToElement(element)
}
}
}
Your cities has different ref, you don't need to access [0] element
watch: {
letter () {
if (this.letter && this.$refs[this.letter]) {
const element = this.$refs[this.letter]
this.scroll.scrollToElement(element)
}
}
}
I have this dropZone that is clickable and opens up the file selecting thing. And once a file is selected from your computer it gives a preview of it (if it's an image). I would like to be able to drag and drop the same file and it do the same thing as if I were to click in the div and open up a file.
I tried calling my handleChange function inside of the onDrop but it didn't quite work and I would get an TypeError: Cannot read property 'target' of undefined error or it just wouldn't do anything at all. Here is a CodeSandbox of the dropzone component on it's own.
Here's that snippet of my code:
class DropZone extends Component {
constructor(props){
super(props)
this.state = {
file: "",
fileId: uuid(),
className: 'dropZone'
}
this.handleChange = this.handleChange.bind(this)
this._onDragEnter = this._onDragEnter.bind(this);
this._onDragLeave = this._onDragLeave.bind(this);
this._onDragOver = this._onDragOver.bind(this);
this._onDrop = this._onDrop.bind(this);
}
handleChange(event) {
this.setState({
file: URL.createObjectURL(event.target.files[0])
})
console.log("handleChange")
//document.getElementsByClassName("dropZone").style.backgroundImage = 'url(' + this.state.file + ')';
}
componentDidMount() {
window.addEventListener('mouseup', this._onDragLeave);
window.addEventListener('dragenter', this._onDragEnter);
window.addEventListener('dragover', this._onDragOver);
document.getElementById('dragbox').addEventListener('dragleave', this._onDragLeave);
window.addEventListener('drop', this._onDrop);
}
componentWillUnmount() {
window.removeEventListener('mouseup', this._onDragLeave);
window.removeEventListener('dragenter', this._onDragEnter);
window.addEventListener('dragover', this._onDragOver);
document.getElementById('dragbox').removeEventListener('dragleave', this._onDragLeave);
window.removeEventListener('drop', this._onDrop);
}
_onDragEnter(e) {
e.stopPropagation();
e.preventDefault();
return false;
}
_onDragOver(e) {
e.preventDefault();
e.stopPropagation();
return false;
}
_onDragLeave(e) {
e.stopPropagation();
e.preventDefault();
return false;
}
_onDrop(e, event) {
e.preventDefault();
this.handleChange
let files = e.dataTransfer.files;
console.log('Files dropped: ', files);
// Upload files
//this.handleChange.bind(this)
console.log(this.state.file)
return false;
}
render() {
const uniqueId = this.state.fileId;
return (
<div>
<input type="file" id={uniqueId} name={uniqueId} class="inputFile" onChange={this.handleChange}/>
<label htmlFor={uniqueId} value={this.state.file}>
{this.props.children}
<div className="dropZone" id="dragbox" onChange={this.handleChange}>
Drop or Choose File
<img src={this.state.file} id="pic" name="file" accept="image/*"/>
</div>
</label>
<div>
</div>
</div>
);
}
}
There's going to be multiple of these that upload their own individual photo/file. Thanks!
You needed to pass on the e parameter to handleChange() and correctly grab the files from the event.
onDrop
_onDrop(e, event) {
e.preventDefault();
this.handleChange(e.dataTransfer.files[0]);
let files = e.dataTransfer.files;
console.log("Files dropped: ", files);
// Upload files
console.log(this.state.file);
return false;
}
handleChange
handleChange(file = "") {
this.setState({
file: URL.createObjectURL(file)
});
//document.getElementsByClassName("dropZone").style.backgroundImage = 'url(' + this.state.file + ')';
}
And in render do parsing of the event to get the file:
onChange={e => this.handleChange(e.target.files[0])}
Alternatively, you could make two handleChange to clean mess up your render method.
Link to working example: https://codesandbox.io/s/7k6y94k6w6 (based on your code)
I have a parent which is a form.
This form is composed of two child components:
experiment create (parent)
creation-dataset (child)
creation-metadata (child)
I use a angular component -> mat-accordion to navigate through the two children components.
I use #Input to have the result of what is filled in the children component into the parent.
I want to submit the form only if a file is chosen for both of them. Therefore, I set a variable (in datasetList[i].fileValid) to say whether a file has been selected. Like this I disabled the button if a file is not updated. To disable the button I called the two function:
isDatasetFilesValid()
isMetadataFilesValid()
However, when the variable changed for the second child component it does not updated the disabled button.
This works, only if I press "previous" and "next". The button is not disabled anymore. Like if I needed to reload or refresh the parent. Maybe because of the life cycle ?
Parent Component:
export class ExperimentCreateComponent implements OnInit {
data: any = {};
datasetList: any = [{ fileValid: false }];
metadataList: any = [{ fileValid: false }];
// Functions to navigate through the expansion panels
setStep(index: number) {
this.step = index;
}
nextStep() {
this.step++;
}
prevStep() {
this.step--;
}
isDatasetFilesValid() {
return this.datasetList.findIndex(function(item, i) {
return item.fileValid == false;
});
}
isMetadataFilesValid() {
return this.metadataList.findIndex(function(item, i) {
return item.fileValid == false;
});
}
}
Parent HTML:
<div class="jumbotron">
<div class="container">
<div class="row">
<div class="col-sm-8 offset-sm-2">
<form name="form" (ngSubmit)="f.form.valid" #f="ngForm" novalidate>
<mat-accordion class="headers-align">
<mat-expansion-panel id="datasetUpload" [expanded]="step === 0" (opened)="setStep(1)" hideToggle="true">
<app-creation-dataset [datasetList]="datasetList"></app-creation-dataset>
<mat-action-row>
<button mat-button color="warn" (click)="prevStep()">Previous</button>
<button mat-button color="primary" (click)="nextStep()">Next</button>
</mat-action-row>
</mat-expansion-panel>
<mat-expansion-panel id="metadataUpload" [expanded]="step === 1" (opened)="setStep(2)" hideToggle="true">
<app-creation-metadata [metadataList]="metadataList"></app-creation-metadata>
<mat-action-row>
<button mat-button color="warn" (click)="prevStep()">Previous</button>
<button mat-button color="primary" type="submit" [disabled]="(isMetadataFilesValid() != -1) && (isDatasetFilesValid() != -1)" (click)="createExperiment()">End</button>
</mat-action-row>
</mat-expansion-panel>
</mat-accordion>
</form>
</div>
</div>
</div>
</div>
Child Component:
export class CreationDatasetComponent implements OnInit {
#Input() datasetList: any = [{ fileValid: false }];
fileSelected: File;
constructor(private papa: Papa, private cd: ChangeDetectorRef) {}
ngOnInit() {}
onChange(files: FileList, index: number, dom: any) {
// Option to parse the file with papaparse
let options = {
header: true,
error: (err, file) => {
this.datasetList[index].fileValid = false;
alert(
"Unable to parse CSV file, please verify the file can be accessed and try again. Error reason was: " +
err.code
);
return;
},
complete: (results, file) => {
console.log("Parsed:", results, file);
let filename = file.name;
// Add the dataset to the datasetList
this.datasetList[index].headers = results.meta.fields;
this.datasetList[index].values = results.data;
this.datasetList[index].filename = filename;
this.datasetList[index].is_metadata = false;
this.datasetList[index].fileValid = true;
this.cd.detectChanges();
}
};
this.fileSelected = files[0]; // Get the file
// Call the function to parse the file, option is the callback
this.papa.parse(this.fileSelected, options);
}
// Add a dataset form
addDataset() {
this.datasetList.push({ fileValid: false });
}
// Remove a dataset form
removeDataset(index: number) {
this.datasetList.splice(index, 1);
}
}
Child HTML:
<div *ngFor="let dataset of datasetList; let index = index">
<div id="datasetFiles">
<h6>Select the type of dataset and browse the files:</h6>
<div class="container">
<div class="row justify-content-between">
<div class="col-6 d-flex align-items-center">
<input id="file" #file (change)="onChange(file.files, index, $event.currentTarget)" type="file">
</div>
</div>
</div>
</div>
</div>
<div>
<button mat-icon-button color="primary" (click)="addDataset()">
<mat-icon>add_box</mat-icon>
</button>
</div>
So, to make this answer more clear, read comments on question.
I'm going to past the example for the #Output:
this is the CHILD.COMPONENT.TS
#Component({
selector: 'children',
templateUrl: './children.component.html',
styleUrls: ['./children.component.scss'],
providers: [{...
})
})
export class ChildrenComponent {
#Output() editedEmitter = new EventEmitter<number>();
private variableToPass = 10;
constructor() {}
functionToCall() {
this.editedEmitter.emit(20);
}
this is the PARENT.COMPONENT.HTML
<section>
<children (editedEmitter)="updateValue($event)"></children>
</section>
<!-- in the component you'll do
updateValue(val: number) {
this.variableToUpdate = val;
}
-->
[disabled] requires a condition (true or false), the code you put in: isMetadataFilesValid() != -1 isDatasetFilesValid() != -1 is not a proper condition, they are two. If you want both conditions to be true, use the && notation.
[disabled]="(isMetadataFilesValid() != -1) && (isDatasetFilesValid() != -1)"
Alternatively I suggest moving the condition to the functions themselves so they return a boolean.