I Don't Understand Any Longer

I don’t know why the * symbol is the only operator passing even after i stated the conditions. Take a look at the equalBtn event listener. * is always passing, and i don’t know why. Is it that i cannot write an inline if statement inside the bind() method? But then, * is passing which seems it’s fine to do so.

I will be happy if someone could point out the error for me. I have tried by best to look for the error, but i just can’t find it.

https://jsfiddle.net/samolex/thxqkbs2/8/

I might not be as far along as you are… but I hate it when no one answers my questions, so here is one thing that I saw:

you have: const collectUserInput = calculationType => {

but I think that you need the parenthesis if you have no parameter:
const collectUserInput = calculationType () => {

I’ll keep looking at your logic and see if I can work it out, but I was hoping just adding the parenthesis would fix it.

1 Like

It has a exactly one argument, calculationType, and that’s why i omitted the parentheses.

Thanks for willing to help, and not just ignoring my problem!

the IDE complains with that. Except if you mean’t this: (calculationType) => {}

You’re misusing .bind() method quite a bit, it must not be used like this. .bind() will forever attach provided arguments to the function (in the same way it binds this to it)

This is an example of correct handler function, see if you can integrate it in your code:

function handleOperatorClick(e) {
  e.preventDefault(); // Just in case button is a descendant of the form
  collectInput(e.target.value); // You will have to introduce `value` attribute for the button
}

document.querySelectorAll('.operator-button')
  .forEach((btn) => btn.addEventListener('click', handleOperatorClick);

Good luck!

Thanks for replying! Your example is hard for me to grasp - i am still a beginner.
maybe you could write an example based on mine

Your code uses more advanced functions than the one I’ve provided :slight_smile: Here is human transcript if it would help you to grasp:

Select all elements with .operator-button class and for each element add event listener with handleOperatorClick function that will in turn pass value attribute of the element to collectInput function

1 Like

This is kind of what i wrote initially. But i refactored the code since i wanted to practice the bind method. But now you are saying i am misusing it. If so, how? and my most important question is why the ternary operator in the bind function is not working correctly. Although, i haven’t seen a ternary operator in a bind function, but since it allows inline if…else, I just thought it should work.

Thank you for your time once again.

equalBtn.addEventListener(

  'click',

  calculateAndWrite.bind(

    this,

    calculationOperator === 'addition'

      ? '+'

      : calculationOperator === 'subtract'

      ? '-'

      : calculationOperator === 'divide'

      ? '/'

      : '*', writer

  )

)

This function is called immediately passing (and locking) current value of calculationOperator at the invocation time with value of undefined forever enclosing * (default case) as argument for any click event from = button

1 Like

Note, that in theory it is fine to use .bind() with other operators the way you do, it’s just not very proper from re-usability point of view + you have to manually attach callback four times

1 Like

Looks like i am getting it a little bit. But why would it be undefined at the invocation time when i initialisedlet calculationOperator; from onset at line 11 in my IDE and set it at line 19 before the calculateAndWrite function was called? And I even used it before that time. Forgive me if my question is rather stupid.

This is how uninitialized variable looks like. Here you only declare variable without giving it initial value and thus it’s value is undefined. If you don’t declare it you will get Reference Error

Don’t mind me. I was saying the same thing. I tried it just now by initializing the the calculationOperator variable with the value of 'addition' and i get the plus symbol passed.

But then, at the top i declared it as a global variable. And inside the first function i set it to a value. And in fact, inside the calculateAndWrite function it is defined. It now looks like its only the equalBtn.addEvent.. that is reading it as undefined . It works fine if i manually initialise the calculationOperator with a value, for example, 'addition'…Let me post the whole code again.

I don’t want to write a new logic, but you could just point out what to replace or add based on what i have written. I also want to keep that bind() 'cause my goal is to work with the bind() method.
I am tired of starring at the code over and over again!

Thanks for your continual help! At least i have been able to spot what is really not right - based on my understanding at the moment.

const inputBtn = document.querySelector('#input-number');

const addBtn = document.querySelector('#btn-add');

const subtractBtn = document.querySelector('#btn-subtract');

const multiplyBtn = document.querySelector('#btn-multiply');

const divideBtn = document.querySelector('#btn-divide');

const equalBtn = document.querySelector('#btn-equal');

const outputArea = document.querySelector('#current-result');

const calculationDescription = document.querySelector('#current-calculation');

let userInput1;

let calculationOperator;

const collectUserInput = calculationType => {

  userInput1 >= 0 || userInput1 // test if user in put is set

    ? (userInput1 = outputArea.textContent)

    : (userInput1 = inputBtn.value);

  inputBtn.value = '';

  inputBtn.focus();

  calculationOperator = calculationType;

};

const calculateAndWrite = (operator, cb) => {

  if (!inputBtn.value) {

    return;

  }

  const userInput2 = inputBtn.value;

  let result;

  calculationOperator === 'addition'

    ? (result = +userInput1 + +userInput2)

    : calculationOperator === 'multiply'

    ? (result = +userInput1 * +userInput2)

    : calculationOperator === 'divide'

    ? (result = +userInput1 / +userInput2)

    : (result = +userInput1 - +userInput2);

  inputBtn.value = '';

  

  // calculationOperator returns the correct operation, but not operator

  // unlesss i initialise calculationOperator with a value from where i declared it 

  console.log(calculationOperator, operator); 

  cb(result, operator, userInput2); 

};

const writer = (result, operator, userInput2) => {

  outputArea.textContent = result;

  calculationDescription.textContent = `${userInput1} ${operator} ${userInput2}`;

};

addBtn.addEventListener('click', collectUserInput.bind(this, 'addition'));

subtractBtn.addEventListener('click', collectUserInput.bind(this, 'subtract'));

multiplyBtn.addEventListener('click', collectUserInput.bind(this, 'multiply'));

divideBtn.addEventListener('click', collectUserInput.bind(this, 'divide'));

equalBtn.addEventListener(

  'click',

  calculateAndWrite.bind(

    this,

    calculationOperator === 'addition'

      ? '+'

      : calculationOperator === 'subtract'

      ? '-'

      : calculationOperator === 'divide'

      ? '/'

      : '*',

    writer

  )

);

I have even replace the ternary operator.

equalBtn.addEventListener('click', calculateAndWrite.bind(this, calculationOperator, writer)); Now i get in the console a big undefined in calculationOperator stead. Does it now mean that the bind function cannot read the outside variable?

addition undefined is what i get from console.log(calculationOperator, operator); on a addition calculation.

You don’t need to use bind, as you’re adding one event listener for four possible operators! It’s fine to use it with operator buttons, again, as each button corresponds to just one operator. Equal sign button CANNOT have bind as it will bind operator with the function you’re passing and you won’t be able to change this. Bind means “attach forever”.

More technically, bind() will be invoked immediately as you’re passing it as a callback to addEventListener method, before there are any events.

1 Like

Thank you very much. I understood the bind function wrongly. My understanding was that it prepares another function to run… Though it prepares, but i missed the part that it executes even before the function is called.
I now know why everything seems weird.

Thanks once again!

You have even solved it here. But just a bit technical.

Sorry for the stresses.

Hey @snigo, don’t know if you are around. I need a little bit of help on the bind thing.

After I learn’t about the this keyword, call() and apply() and even a bit more about bind(), and since you explained to me the last time that the arguments of the bind method are locked - in on the current state of the arguments, I am wondering why the code below will work since, when the browser parses the code, prodList is just an empty array.

I know some of the code are redundant, but i couldn’t think of a better code to explain what i am asking.

const productName = prompt('what is the name of your product?', 'A Product');
const price = prompt('product price', '$ 10');

class Product {
  constructor(...otherProps) {
    this.pname = productName;
    this.price = price;
    this.otherProps = otherProps;
  }
}

const products = {
  prodList: [],
  renderProducts() {
    this.prodList.push(new Product('SKU', 'description'))
    this.prodList.forEach(element => {
    console.log(element)
    });
  }
}

// products.renderProducts()
let { renderProducts } = products; // say i pull it out to use elsewhere

renderProducts = renderProducts.bind(products); // trying out this though

renderProducts();

When you run renderProducts() following lines get executed with this bound to products object

There is nothing unexpected happening here. “Bounding” is nothing else than constant assignment, like so: /* Pseudo */ const this = products, the fact that this points to products doesn’t mean products cannot change, just like in the case with variables

1 Like

Thanks for replying.

The above is what you said. Since what this refers to is products, which has prodList as an empty array when the browser parses the entire code, and this is one of the arguments of the bind() then it should lock it as that just like the calculationOperator variable - I changed , but didn’t work.

Just like it won’t work with const variable:

const THIS_1 = '+';
const THIS_2 = { products: [] };

THIS_1 = '-'; // ERROR
THIS_2.products.push('product');

console.log(THIS_1); // +
console.log(THIS_2); // { products: ['product'] }
1 Like