Please Help - JS Calculator. React. Story 13

Hi, I know it’s a common problem and I’ve studied other solutions, but to be honest still don’t get or ‘click’ how to make it work in my project.

So 5*-5 should give -25. It gives - 25, but then I got an error and in the description of the error says that 5*-+5 should give 10. And it doesn’t.

My code is here: https://github.com/TyroniUA/calculator

Also here:

import React, { createRef } from 'react'
const endsWithOperator = /[*+‑]$/;

class CalculatorTest extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            formula:'',
            input: '0',
            previousValue: '',
            currentValue: '',
        }
        this.handleCLick = this.handleCLick.bind(this);
    }
g

    handleCLick = (event) => {
       if ((this.state.input =='0')){
           console.log('zero' + this.state.input)
           this.setState({
               formula: '' + event.target.value,
               input:'' + event.target.value
           })
           
        }
        else {this.setState({
            formula: this.state.formula + event.target.value,
            input: this.state.input + event.target.value})
       }
        
    }
    adding = () => {
        this.state.previousValue = this.state.input;
        this.setState({
            formula: this.state.formula + '+',
            input: ''
        })
        this.state.operator = 'plus'
    }
    subtract = () => {
        this.state.previousValue = this.state.input;
        this.setState({
            formula: this.state.formula + '-',
            input: ''
        })
        this.state.operator = 'subtract'
    }
    divide = () => {
        this.state.previousValue = this.state.input;
        this.setState({
            formula: this.state.formula + '/',
            input: '/'
        })
        this.state.operator = 'divide'
    }
    multiply = () => {
        this.state.previousValue = this.state.input;
        this.setState({
            formula: this.state.formula + '*',
            input: ''
        })
        this.state.operator = 'multiply'
    }
    addDecimal = (event) => {
        // only add decimal if there is no current decimal point present in the input area
        
        if (this.state.input.indexOf(".") === -1) {
          this.setState({ 
            formula: this.state.formula + event.target.value,  
            input: this.state.input + event.target.value });
        }
      };
    clear = () => {
        this.setState({
            input: '0',
            formula: '0'
        })

        this.state.previousValue = '';
        this.state.currentValue = ''
}
    
    equals = () => {
       let result = this.state.formula.split('');
       
       console.log('this is' + result[1])
       while ( endsWithOperator.test(result)) {
            console.log('slicing')
            result = result.slice(0, -1);
          }
        result = eval(result);
        // the code that works without trying to solve Problem 13:
        // let result = eval(this.state.formula.toString())
        
       this.setState({
           /*formula: this.state.formula + ' = ' + eval(this.state.formula.toString()),*/
           formula: result,
           input: result
        }
       )
       
    }
    render() {

        return (
            <div><h1>TEST</h1>
            <div id='calculator'>
                <div id='formula'>{this.state.formula}</div>
                <div id='display'>{this.state.input}</div>
                {console.log(this.state.previousValue, this.state.input)}
                <div id='row' >
                    <button id='seven' ref={event => createRef(event)} value='7' onClick={this.handleCLick}>7</button>
                    <button id='eight' ref={event => createRef(event)} value='8' onClick={this.handleCLick}>8</button>
                    <button id='nine' ref={event => createRef(event)} value='9' onClick={this.handleCLick}>9</button>
                    <button id='divide' ref={event => createRef(event)} onClick={this.divide} value='/'>/</button>
                </div>
                <div id='row' >
                    <button id='four' ref={event => createRef(event)} value='4' onClick={this.handleCLick}>4</button>
                    <button id='five' ref={event => createRef(event)} value='5' onClick={this.handleCLick}>5</button>
                    <button id='six' ref={event => createRef(event)} value='6' onClick={this.handleCLick}>6</button>
                    <button id='multiply' ref={event => createRef(event)} onClick={this.multiply} value='*'>x</button>
                </div>
                <div id='row' ><button id='one' ref={event => createRef(event)} value='1' onClick={this.handleCLick}>1</button>
                    <button id='two' ref={event => createRef(event)} value='2' onClick={this.handleCLick}>2</button>
                    <button id='three' ref={event => createRef(event)} value='3' onClick={this.handleCLick}>3</button>
                    <button id='add' ref={event => createRef(event)} onClick={this.adding} value='+'>+</button>
                </div>
                <div id='row' >
                    <button id='decimal' ref={event => createRef(event)} onClick={this.addDecimal} value='.'>.</button>
                    <button id='zero' ref={event => createRef(event)} value='0' onClick={this.handleCLick}>0</button>
                    <button id='clear' ref={event => createRef(event)} onClick={this.clear} value='AC' >AC</button>
                    <button id='subtract' ref={event => createRef(event)} onClick={this.subtract} value='-' >-</button>
                    </div>
                    <button id='equals' ref={event => createRef(event)} onClick={this.equals} value='='>=</button>
                

            </div>
            </div>
        )
    }
}

export default CalculatorTest

Correct. How are you preventing the calculator from accepting an input of chained operators. i.e 5+/*+++5

Also, just skimming the code, can I do 1.1+2.2?

1.1. + 2.2. gives a result but it should be rounded. Regarding preventing - I actually don’t. I was trying to put out excess of operators from the formula, but you make me think otherwise :slight_smile: So basiclly I should prevent with simple if statement (if last input was +*/ => interchange) - will that logic work?

Ah i see now, you are breaking the formula down. Then creating a master formula. I like your approach!

And what you have suggested should work, I’m just trying to visualize your code by reading it.

The - is going to be a little tricky because +- is valid. So you can’t just look at the last digit in the formula :wink:

Like the test says 5*-+5 should give 10 (5+5=10) so the + will skip back to * and replace both *-

…again, I can’t run your code and test it, just trying to visualize it in my head :rofl:

Trying to prevent, but still doesn’t work.

    handleCLick = (event) => {
        if (this.state.input == '0') {
            console.log('zero' + this.state.input)
            this.setState({
                formula: '' + event.target.value,
                input: '' + event.target.value
            })

        }
        else if (!endsWithOperator.test(this.state.formula)) {
            console.log('Im testing')
            this.setState({
                previousValue: this.state.formula,
                formula: this.state.formula + event.target.value
            })
            console.log(this.state.previousValue);
        }
        else if (!endsWithNegativeSign.test(this.state.formula)) {
            console.log('negative sign')
            this.setState({
                formula: (endsWithNegativeSign.test(this.state.formula + event.target.value) ? this.state.formula : this.state.previousValue) + event.target.value
            })
            
        }
        else if (event.target.value !== "‑") {
            console.log('it also doing something')
            this.setState({
                formula: this.state.previousValue + event.target.value
            })

        }
        else {
            this.setState({
                formula: this.state.formula + event.target.value,
                input: this.state.input + event.target.value
            })
        }

    }

But problem is that I don’t see log of ‘I’m stesting’ and only see log of ‘negative sign’ and result is basically 5.

UPD: Got the issue - my each operator handles with each separate function, so basically created one united for operators and put that logic there and currently at least I see logs.

What is this function? And what is endsWithNegativeSign ?

Also this is a lot of code for trying to find the last couple digits in this.state.formula

I also took another look at the code and see more redundancy, for example:

adding = () => {
        this.state.previousValue = this.state.input;
        this.setState({
            formula: this.state.formula + '+',
            input: ''
        })
        this.state.operator = 'plus'
    }
    subtract = () => {
        this.state.previousValue = this.state.input;
        this.setState({
            formula: this.state.formula + '-',
            input: ''
        })
        this.state.operator = 'subtract'
    }
    divide = () => {
        this.state.previousValue = this.state.input;
        this.setState({
            formula: this.state.formula + '/',
            input: '/'
        })
        this.state.operator = 'divide'
    }
    multiply = () => {
        this.state.previousValue = this.state.input;
        this.setState({
            formula: this.state.formula + '*',
            input: ''
        })
        this.state.operator = 'multiply'
    }

what is this.state.operator ? is it ever actually used? Can you get the value from the target to make this all 1 function?

I know that doesn’t solve your current issue, but I just wanted to point out an area where you could clean the code up. (and make life easier to debug in the future)

Hi, yes there is lot of rubbish code I didn’t clear because of previous work. Currently clear everything and here it is. I also manage to find a solution, but currently during the test all my programme crashes lol :slight_smile: That coding… That life… Push another master to git and also here is the new calculatorTest.js

import React, { createRef } from 'react'
const endsWithOperator = /[*+‑]$/;
const endsWithNegativeSign = /[x/+]‑$/;

class CalculatorTest extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            formula:'',
            input: '0',
            previousValue: '',
            currentValue: '',
        }
        this.handleCLick = this.handleCLick.bind(this);
    }


    handleCLick = (event) => {
        if (this.state.input === '0') {
            //console.log('zero' + this.state.input)
            this.setState({
                formula: '' + event.target.value,
                input: '' + event.target.value
            })

        }
        
        else {
            console.log('HandleCLick else statement')
            this.setState({
                formula: this.state.formula + event.target.value,
                input: this.state.input + event.target.value
            })
        }
    }
    handleOperator =(event)=> {
        console.log(event.target.value)
        if (!endsWithOperator.test(this.state.formula)) {
            console.log('Im testing')
            this.setState({
                previousValue: this.state.formula,
                formula: this.state.formula + event.target.value,
                input: ''
            })
            console.log(this.state.formula);
        }
        
        else if (!endsWithNegativeSign.test(this.state.formula)) {
            console.log('HandleOperator endsWithNegativeSign')
            this.setState({
                formula: (endsWithNegativeSign.test(this.state.formula + event.target.value) ? this.state.formula : this.state.previousValue) + event.target.value,
                })
        }

        else if (event.target.value !== '‑') {
            console.log('it also doing something')
            this.setState({
                formula: this.state.previousValue + event.target.value
            })

        }
    }
    
    addDecimal = (event) => {
        // only add decimal if there is no current decimal point present in the input area
        
        if (this.state.input.indexOf(".") === -1) {
          this.setState({ 
            formula: this.state.formula + event.target.value,  
            input: this.state.input + event.target.value });
        }
      };
    clear = () => {
        this.setState({
            input: '0',
            formula: '0',
            previousValue: '',
            currentValue: ''
        })

}
    
    equals = () => {
       
        // the code that works without trying to solve Problem 13:
        let result = eval(this.state.formula.toString())
        
       this.setState({
           /*formula: this.state.formula + ' = ' + eval(this.state.formula.toString()),*/
           formula: result,
           input: result
        }
       )
       
    }
    render() {

        return (
            <div><h1>TEST</h1>
            <div id='calculator'>
                <div id='formula'>{this.state.formula}</div>
                <div id='display'>{this.state.input}</div>
                {/*console.log(this.state.previousValue, this.state.input)*/}
                <div id='row' >
                    <button id='seven' ref={event => createRef(event)} value='7' onClick={this.handleCLick}>7</button>
                    <button id='eight' ref={event => createRef(event)} value='8' onClick={this.handleCLick}>8</button>
                    <button id='nine' ref={event => createRef(event)} value='9' onClick={this.handleCLick}>9</button>
                    <button id='divide' ref={event => createRef(event)} onClick={this.handleOperator} value='/'>/</button>
                </div>
                <div id='row' >
                    <button id='four' ref={event => createRef(event)} value='4' onClick={this.handleCLick}>4</button>
                    <button id='five' ref={event => createRef(event)} value='5' onClick={this.handleCLick}>5</button>
                    <button id='six' ref={event => createRef(event)} value='6' onClick={this.handleCLick}>6</button>
                    <button id='multiply' ref={event => createRef(event)} onClick={this.handleOperator} value='*'>x</button>
                </div>
                <div id='row' ><button id='one' ref={event => createRef(event)} value='1' onClick={this.handleCLick}>1</button>
                    <button id='two' ref={event => createRef(event)} value='2' onClick={this.handleCLick}>2</button>
                    <button id='three' ref={event => createRef(event)} value='3' onClick={this.handleCLick}>3</button>
                    <button id='add' ref={event => createRef(event)} onClick={this.handleOperator} value='+'>+</button>
                </div>
                <div id='row' >
                    <button id='decimal' ref={event => createRef(event)} onClick={this.addDecimal} value='.'>.</button>
                    <button id='zero' ref={event => createRef(event)} value='0' onClick={this.handleCLick}>0</button>
                    <button id='clear' ref={event => createRef(event)} onClick={this.clear} value='AC' >AC</button>
                    <button id='subtract' ref={event => createRef(event)} onClick={this.handleOperator} value="‑">-</button>
                    </div>
                    <button id='equals' ref={event => createRef(event)} onClick={this.equals} value='='>=</button>
                

            </div>
            </div>
        )
    }
}

export default CalculatorTest
1 Like

This looks 100% better!! Congrats!

Still it collapses with 3+5*6‑2 claculation. Cannot get why…

Can somebody help me with this? Now it crashes on user story 10 with ‘3+5*6‑2’ and eval. I’m not sure why, but it cannot handle this evaluation in my solution.