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.
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'm attempting to load Youtube Videos via their API, and in order to get the duration, I have to send a second API request. The issue I'm having is that sometimes this code works, sometimes it throws
Error in render: "TypeError: Cannot read property 'contentDetails' of undefined"
I think it is because when Vue is trying to access the property, it is not there. If I access the variable (resolvedVideoData) with the Vue Developer tool on a failed load, it has only resolved ONE video.
What am I doing wrong? I'm calling the API query in created(), so the DOM hasn't loaded yet?
<script>
import axios from 'axios';
import moment from 'moment'
export default {
name: 'BlogGrid',
data(){
return {
videos:[],
base_url_youtube: 'http://www.youtube.com/watch?v=',
videoId: [],
resolvedVideoData: [],
}
},
watch: {
videos: function (){
var arrayLength = this.videos.length;
for (var i = 0; i < arrayLength; i++) {
this.videoId.push(this.videos[i].id.videoId);
}
this.getVideoDuration()
}
},
created() {
axios.get(`https://www.googleapis.com/youtube/v3/search?key={{YOUTUBE_API_KEY}}&channelId={{ChannelID}}A&order=date&part=snippet%20&type=video,id&maxResults=50`)
.then(response => {
this.videos = response.data.items
})
.catch(e => {
this.errors.push(e)
})
},
methods: {
getVideoDuration(){
axios.get('https://www.googleapis.com/youtube/v3/videos?id=' + this.videoId.join(', ') + '&part=contentDetails&key={{YOUTUBE_API_KEY}}')
.then(response => {
this.resolvedVideoData = response.data.items
})
.catch(e => {
this.errors.push(e)
})
}
}
}
</script>
Upon further checking, if I spam the generated URL for the Google API, it seems like sometimes it's returning one value, sometimes it's returning all the values.
Since it was asked for
<section class="blog-area ptb-80">
<div class="container">
<div class="row">
<div
v-for="(item, index) in videos"
:key="item.etag"
class="col-lg-4 col-md-6"
>
<div class="single-blog-post">
<div
class="blog-image"
:href="base_url_youtube + item.id.videoId "
>
<a :href="base_url_youtube + item.id.videoId ">
<img
:src="item.snippet.thumbnails.high.url"
name="videoicon"
alt="image"
></a>
<a :href="base_url_youtube + item.id.videoId ">
<div class="overlay hidden-sm">
<div class="text">
{{ parseDuration(resolvedVideoData[index].contentDetails.duration) }}
<br>
<a :href="base_url_youtube + item.id.videoId"> <feather type="monitor" /></a>
</div>
</div>
</a>
<div class="date">
<feather type="calendar" />
{{ format_date(item.snippet.publishedAt ) }}
</div>
<div class="blog-post-content">
{{ item.snippet.title }}
</div>
</div>
</div>
</div>
</div>
</div>
</section>
with my other methods being.
format_date(value){
if (value) {
return moment(String(value)).format('DD-MM-YYYY')
}
},
parseDuration(e){
var n = e.replace(/D|H|M/g,":").replace(/P|T|S/g,"").split(":");
if(1 == n.length)
2!=n[0].length && (n[0]="0"+n[0]),n[0]="0:"+n[0];
else
for(var r=1, l=n.length-1; l>=r;r++)
2!=n[r].length && (n[r]="0"+n[r]);
return n.join(":")
},
I want to render data from API which I render it through for loop but when I'm displaying it to UI, it displays only 1 value.
Specification: - when user upload a text image, API displays text which is present in the image and name, which is the JSON data is an array so I render DetectedText value-form API using for loop but not able to display all value of DetectedText in UI so please tell me where I'm doing wrong please see the below code
import React, { Component } from 'react';
import axios from 'axios'
class Image extends Component {
constructor(props) {
super(props);
this.state = { file: '', imagePreviewUrl: '', selectedOption: '', change: [], response: [], path: [], jsonData: [], dText: [] };
}
handleSubmit(e) {
e.preventDefault();
var byteCode = this.state.imagePreviewUrl.substring((e.target.value).indexOf(',') + 23);
let url = "http://192.168.4.138/MediaAnalysisImage_Amazon/api/DetectText/DetectText";
const data = { "fileByte": byteCode }
const response = axios.post(url, data)
.then(response => {
this.setState({
change: response,
byteArr: response.data.fileByte,
jsonData: response.data.jsondata.replace(/[&\/\\#+()$"~%.'*?<>{}]/g, ''),
path: response.data.jsondata.DetectedText,
});
console.log('json detected data', this.state.jsonData)
const parseData = JSON.parse(response.data.jsondata)
let x = ""
for (let x of parseData) {
const DetectedText = x.DetectedText
this.setState({
dText: DetectedText
})
console.log('setting dtext', this.state.dText)
}
})
}
handleImageChange(e) {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
this.setState({
file: file,
imagePreviewUrl: reader.result
});
}
reader.readAsDataURL(file)
}
render() {
const img = "data:image/png;base64" + ',' + this.state.byteArr
let { imagePreviewUrl } = this.state;
let $imagePreview = null;
if (imagePreviewUrl) {
$imagePreview = (<img src={imagePreviewUrl} className="img-responsive imgp" />);
} else {
$imagePreview = (<span className="previewText">Please select an Image for Preview</span>);
}
return (
<div className="wrapper">
<h2 className="text-center heading" >Text Recognization</h2>
<div className="container ">
<section className="celeb">
<form className="Fform bg-light mb-4">
<div class="form-group ">
<input className="fileInput"
type="file"
onChange={(e) => this.handleImageChange(e)} class="btn btn-secondary" />
</div>
<button className="btn btn-success"
type="submit"
onClick={(e) => this.handleSubmit(e)}>Upload Image</button>
</form>
<hr></hr>
<div className="row grid">
<div className="col-md-6">
<h3>Input Image</h3>
{$imagePreview}
</div>
<div className="col-md-6">
<h3>Output Image</h3>
<img src={img} className="img-responsive imgp" />
</div>
</div>
<div>
<hr></hr>
<h4>Description </h4>
<table className="table table-hover">
<tr>
<th ><label>Name :- </label></th>
<td>{this.state.dText}</td>
</tr>
</table>
</div>
</section>
</div>
</div>
)
}
}
export default Image;
You may change like this:
this.setState({
dText: parseData.map(x => x.DetectedText),
})
and in your render method:
<td>{ this.state.dText.map((text, index) => <div key={index}>{text}</div>) }</td>
I'm developing a WP Gutenberg block based on https://github.com/JimSchofield/Guty-Blocks-2 and I'm running into an issue where the saved content doesn't match the editor when loaded therefore I'm seeing an error 'This block contains unexpected or invalid content'.
I have tried looking in the browser console but I can't figure out where the discrepancy is, both the edit and save functions reference the images but they're not being stored by the save function.
It's worth noting that once the block is loaded for the first time, used and the post is saved it works correctly on the front-end. It's when you go back to the editor it doesn't work anymore.
import './__block__.view.scss';
import './__block__.editor.scss';
const {
registerBlockType,
getBlockDefaultClassName
} = wp.blocks;
const {
InspectorControls,
MediaUpload
} = wp.editor;
const {
Button
} = wp.components;
registerBlockType('__namespace__/__block__', {
title: '__prettyname__(noCase)',
icon: '__icon__',
category: '__category__',
attributes: {
imgUrl: {
type: 'array',
source: 'children',
selector: 'img',
},
},
edit({ attributes, className, setAttributes }) {
//Destructuring the images array attribute
const {images = []} = attributes;
// This removes an image from the gallery
const removeImage = (removeImage) => {
//filter the images
const newImages = images.filter( (image) => {
//If the current image is equal to removeImage the image will be returnd
if(image.id != removeImage.id) {
return image;
}
});
//Saves the new state
setAttributes({
images:newImages,
})
}
//Displays the images
const displayImages = (images) => {
return (
//Loops throug the images
images.map( (image) => {
return (
<div className="gallery-item-container">
<img className='gallery-item' src={image.url} key={ images.id } />
<div className='remove-item' onClick={() => removeImage(image)}><span class="dashicons dashicons-trash"></span></div>
<div className='caption-text'>{image.caption[0]}</div>
</div>
)
})
)
}
//JSX to return
return (
<div>
<MediaUpload
onSelect={(media) => {setAttributes({images: [...images, ...media]});}}
type="image"
multiple={true}
value={images}
render={({open}) => (
<Button className="select-images-button is-button is-default is-large" onClick={open}>
Add images
</Button>
)}
/>
<br />
<div class="modal__img">
<div class="flexslider">
<ul class="slides" data-total-slides={images.length}>{ displayImages(images) }</ul>
</div>
</div>
</div>
);
},
save({attributes}) {
// Destructuring the images array attribute
const { images = [] } = attributes;
// Displays the images
const displayImages = (images) => {
return (
images.map( (image,index) => {
return (
<li><img
className='lazy'
key={images.id}
data-src={image.url}
data-slide-no={index}
data-caption={image.caption[0]}
alt={image.alt}
/></li>
)
})
)
}
//JSX to return
return (
<div class="modal__img">
<div class="flexslider">
<ul class="slides" data-total-slides={images.length}>{ displayImages(images) }</ul>
</div>
</div>
);
},
});
I expected the block to output the original HTML when back in the editor, but this behaviour does not work.
In both the save and edit function your are referencing images from the attributes prop. Yet, when you register your block and set up the attributes, you only have imageUrl as an attribute. This means images are never getting stored in the DB, and do not exist when you come back to edit.
Adding images as a attribute should fix this.
What you have
attributes: {
imgUrl: {
type: 'array',
source: 'children',
selector: 'img',
},
},
What it should be
attributes: {
images: {
type: 'array',
default: []
},
},
Try passing props instead of attributes in edit and save functions, and then simply use
var attributes = props.attributes;
For more reference read the code in these examples.
I have used react dropzone component for multiple image upload but the image preview is not shown on my template.Files are shown on console.Where have i done wrong? I have used this component from here https://github.com/okonet/react-dropzone . let me know what else i have to provide to examine this issue with fine-tooth comb. Thanks for help in advance. Your help will be appreciated.
The code is
var Gallery = React.createClass({
getInitialState: function () {
return {
files:[]
};
},
onDrop(files) {
console.log('Received files: ', files);
this.setState({
files: files
});
},
showFiles() {
var files = this.state;
console.log('files',files);
if (!files.length) {
return null;
}
return (
<div>
<h3>Dropped files: </h3>
<ul className="col-md-4">
{
files.map((file, idx) => {
return (
<li key={idx}>
<img src={file.preview} width={100}/>
<div>{file.name + ' : ' + file.size + ' bytes.'}</div>
</li>
);
})
}
</ul>
</div>
);
},
render: function () {
return (
<div>
<div className="col-md-12">
<Dropzone onDrop={this.onDrop}>
Try dropping some files here, or click to select files to upload.
</Dropzone>
{this.showFiles()}
</div>
<div className="row">
<button className="btn" onClick={this.submit}>Next</button>
</div>
</div>
);
},
});
The problem is in the showFiles method.
var files = this.state;
//const {files}=this.state
you don't assign the files to the file var, but the whole state.
i managed to solve the problem by doing this
var files = this.state.files || null;