0

I can successfully upload to firebase storage and retrieve image URL using promises, but I wanted to link a progress bar to the percent completion of the upload. What I have achieved thus far: When I call this function from a component:

this.props.handleNewPrizeImageUpload(this.progressCallback, this.imageUploadCompletionCallback, prizeImage)

with these callbacks defined in the component:

  progressCallback (progress) {
    **//this.someOtherFunction(progress).bind(this)**
    return console.log('Upload is ' + progress + '% done')

  }

  imageUploadCompletionCallback (url) {
     **//this.props.someOtherFunctionB(url)**
    console.log('SAVEPRIZEIMAGE RAN SUCCESFULLY RETURN URL : ', url)}

this function runs:

export function handleNewPrizeImageUpload (progressCallback, imageUploadCompletionCallback,
  prizeImage) {
  savePrizeImage(progressCallback, imageUploadCompletionCallback,prizeImage)
}

The savePrizeImage is a function that save the image and runs callback back functions accordingly.

I can successfully retrieve the progress value and the URL Data but the Problem I am facing is that I can't use my other defined function within those callbacks to do something the retrieved Data, I keep getting the error that this is not defined. I have tried bind(this) it does not work.

error:

Uncaught TypeError: Cannot read property 'someOtherFunction' of undefined

What I have tried:

  constructor (props) {
    super(props)
    this.someOtherFunction = this.someOtherFunction.bind(this)
  }

and then calling it like so:

  progressCallback (progress) {
    console.log('Upload is ' + progress + '% done')
    this.someOtherFunction(progress)
  }

  someOtherFunction (progress) {
    console.log('HAHAHA')
  }

Heer is the Entire component Code Block:

import React, { Component, PropTypes } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import {CreatePrizeForm} from 'components'
import * as ActionCreators from 'redux/modules/prizes'

export class CreatePrizeFormContainer extends Component {

  static contextTypes = {
    router: PropTypes.object.isRequired
  }

  constructor (props) {
    super(props)
    // this.someOtherFunction = this.someOtherFunction.bind(this)
    // this.progressCallback = this.progressCallback.bind(this)
  }

  handlePrizeData (prizeImage) {
    this.props.handleNewPrizeImageUpload(this.progressCallback, this.imageUploadCompletionCallback, PrizeImage)
  }


  progressCallback (progress) {
    console.log('Upload is ' + progress + '% done')
    //this.someOtherFunction(progress)
  }


  imageUploadCompletionCallback (url) {
    console.log('SAVE TO FIREBASE RAN SUCCESFULLY RETURNED IMAGE URL : ', url)
  }

  someOtherFunction (progress) {
    console.log('HAHAHA')
  }

  render () {
    return (
      <div>
        <CreatePrizeForm addPrizeData = {(prizeImage) => { this.handlePrizeData(prizeImage) }}/>
      </div>
    )
  }
}

function mapStateToProps (state, props) {
  return {
  }
}

function mapDispatchToProps (dispatch, props) {
  return bindActionCreators(ActionCreators, dispatch)
}

export default connect(mapStateToProps, mapDispatchToProps)(CreatePrizeFormContainer)
jasan
  • 8,391
  • 16
  • 45
  • 90

1 Answers1

0

When you pass a reference to a function (e.g. as argument, or other assignment), it will not have its context bound to it.

This is the case with the this.progressCallback argument:

this.props.handleNewPrizeImageUpload(this.progressCallback, ... )

That progressCallback argument variable is not linked to this, even though you pass it like that -- which is the cause of a lot of misunderstanding; you are not the only one.

Solve it as follows:

this.props.handleNewPrizeImageUpload(this.progressCallback.bind(this), ... )

See the very good Q&A on this.

Here is some of your code trimmed down to a working snippet:

"strict"
// Dummy Component class for this snippet only
class Component { constructor (props) { this.props = props } }
// Your class:
class CreatePrizeFormContainer extends Component {
  constructor (props) { super(props) }
  handlePrizeData (prizeImage) {
    this.props.handleNewPrizeImageUpload(
        this.progressCallback.bind(this),
        this.imageUploadCompletionCallback.bind(this), prizeImage)
  }
  progressCallback (progress) {
    console.log('Upload is ' + progress + '% done')
    this.someOtherFunction(progress)
  }
  imageUploadCompletionCallback (url) {
    console.log('SAVE TO FIREBASE RAN SUCCESFULLY RETURNED IMAGE URL : ', url)
  }
  someOtherFunction (progress) { console.log('HAHAHA') }
}
// Dummy savePrizeImage function for this snippet only
function savePrizeImage(progressCallback, imageUploadCompletionCallback, ImageFile) {
  // Simulate two progress events
  setTimeout(function() { progressCallback(50) }, 0)
  setTimeout(function() { progressCallback(100) }, 500)
  setTimeout(function() { imageUploadCompletionCallback('http://example.com') }, 510)
}
// Create instance, passing simple prop literal
var obj = new CreatePrizeFormContainer({ 
  handleNewPrizeImageUpload: function(progressCallback, 
                                      imageUploadCompletionCallback, ImageFile) {
    savePrizeImage(progressCallback, imageUploadCompletionCallback, ImageFile)
  }
})
obj.handlePrizeData('dummyPrizeImage.img') // Call handlePrizeData
Community
  • 1
  • 1
trincot
  • 211,288
  • 25
  • 175
  • 211