Kam Banwait
Kam Banwait

Reputation: 71

Incrementing the Material Design Lite Progress bar with React

I've got MDL running with React at the moment and it seems to be working fine at the moment.

I've got the Progress Bar appearing on the page as needed and it loads up with the specified 'progress' on page load when either entering in a number directly:

document.querySelector('#questionnaireProgressBar').addEventListener('mdl-componentupgraded', function() {
    this.MaterialProgress.setProgress(10);
})

or when passing in a number via a Variable:

document.querySelector('#questionnaireProgressBar').addEventListener('mdl-componentupgraded', function() {
    this.MaterialProgress.setProgress(value);
})

It stops working after this though. I try to update the value via the Variable and it doesn't update. I've been advised to use this:

document.querySelector('.mdl-js-progress').MaterialProgress.setProgress(45);

to update the value but it doesn't work. Even when trying it directly in the console.

When trying via the Console I get the following Error:

Uncaught TypeError: document.querySelector(...).MaterialProgress.setProgress is not a function(…)

When I try to increment the value via the Variable I get no errors and when I console.log(value) I am presented the correct number (1,2,3,4...) after each click event that fires the function (it fires when an answer is chosen in a questionnaire)

What I want to know is if there's something obvious that I'm missing when using MTL and React to make components to work? There was an issue with scope but I seem to have it fixed with the following:

updateProgressBar: function(value) {
    // fixes scope in side function below
    var _this = this;

    document.querySelector('#questionnaireProgressBar').addEventListener('mdl-componentupgraded', function() {
        this.MaterialProgress.setProgress(value);
    })
},

In React I've got the parent feeding the child with the data via props and I'm using "componentWillReceiveProps" to call the function that updates the progress bar.

I've used the "componentDidMount" function too to see if it makes a difference but it still only works on page load. From what I've read, it seems that I should be using "componentWillReceiveProps" over "componentDidMount".

It's being fed from the parent due to components sending data between each other. I've used their doc's and some internet help to correctly update the parent function to then update the progress bar in the separate component.

updateProgressBarTotal: function(questionsAnsweredTotal) {
    this.props.updateProgressBarValue(questionsAnsweredTotal);
}

The parent function looks like the following (I think this may be the culprit):

// this is passed down to the Questions component
updateProgressBarTotal: function(questionsAnsweredTotal) {
    this.setState({
        progressBarQuestionsAnswered : questionsAnsweredTotal
    })
}

I can post up some more of the code if needed.

Thank you

Upvotes: 4

Views: 3004

Answers (3)

Italo Borssatto
Italo Borssatto

Reputation: 15689

After attaching the progress bar to the document, execute:

function updateProgress(id) {
    var e = document.querySelector(id);
    componentHandler.upgradeElement(e);
    e.MaterialProgress.setProgress(10);
}

updateProgress('#questionnaireProgressBar');

Upvotes: 0

MacKentoch
MacKentoch

Reputation: 2446

I had same problem in angular2 application. You don't necessary need to move to the child component.

I found after struggling to find a reasonable fix that you simply have to be sure mdl-componentupgradedevent already occurred before being able to use MaterialProgress.setProgress(VALUE). Then it can be updated with dynamic value.

That is why moving to the child works. In the parent component mdl-componentupgraded event had time to occur before you update progress value

My solution for angular2 in this article

Adapted in a React JS application :

in componentDidMount, place a flag mdlProgressInitDone (initiated to false) in mdl-componentupgraded callback :

// this.ProgBar/nativeElement 
// is angular2 = document.querySelector('.mdl-js-progress')
var self = this;
this.ProgBar.nativeElement.addEventListener('mdl-componentupgraded', function() {
  this.MaterialProgress.setProgress(0);
  self.mdlProgressInitDone = true; //flag to keep in state for exemple
});

Then in componentWillReceiveProps test the flag before trying to update progress value :

this.mdlProgressInitDone ? this.updateProgress() : false;

updateProgress() {
this.ProgBar.nativeElement.MaterialProgress.setProgress(this.currentProgress);  
}

Upvotes: 0

Kam Banwait
Kam Banwait

Reputation: 71

Looks I needed a fresh set of eyes on this.

I moved the function to the child of the parent. It seems that using document.querySelector... when in the parent doesn't find the element but when it's moved to the child where I do all the question logic it seems to be fine. It increments the progress correctly etc now :)

// goes to Questionnaire.jsx (parent) to update the props
updateProgressBarTotal: function(questionsAnsweredTotal) {
    // updates the state in the parent props
    this.props.updateProgressBarValue(questionsAnsweredTotal);
    // update the progress bar with Value from questionsAnsweredTotal
    document.querySelector('.mdl-js-progress').MaterialProgress.setProgress(questionsAnsweredTotal);
},

Upvotes: 3

Related Questions