How to create an array of button elements in p5

I'm trying to create an array of buttons (dom element) which trigger sound files (up to 100). It's difficult for me to figure out how to access each button individually, such that button(index48) returns its own value. This doesn't seem to work:

for (var i=0; i<button.length; i++) {
  button[i]=createButton(i);
  button[i].mousePressed(print(i));
}

Any tips? thanks

Answers

  • edited December 2017
    • I can spot at least 2 bugs in your posted code excerpt above. :-SS
    • 1st 1 is about passing an undefined value as a callback to p5.Element::mousePressed() method instead of a function! #-o
    • How's that happening you may ask? :-/
    • Try out to assign the returned value of a print() call to some variable: const und = print();. :>
    • Then print() that out like this: print('und is : ' + und);. >-)
    • You're gonna get "und is : undefined" as its output! @-)
    • In order to pass an actual callback which runs that desired task, you may for example use the fat arrow => to turn that into a lambda, and pass that as the callback argument for p5.Element::mousePressed(): button[i].mousePressed(() => print(i));. O:-)
  • edited December 2017
    • Now w/ that callback issue solved we can start dealing w/ the 2nd buggy problem... 8-X
    • In JS, the keyword var creates 1 single variable, as we would expect. ~O)
    • However, you're attempting to print() that declared iterator variable i in a later time, when folks finally mousePressed() 1 of those buttons. :!!
    • Now try out to guess which value is stored in that variable i by then? :-?
    • If you answered that iterator variable i should print() the value button.length, you've hit the jackpot! <:-P
    • Recall that variable i is increased by 1 ++ until it reaches the value button.length: L-)
      for (var i = 0; i < button.length; ++i) {.
    • The callbacks there access that single variable i by a JS feature called closure. :-B
    • And they're all gonna get the current value stored by variable i, which is the same as button.length at the end of its loop. ;;)
  • edited December 2017 Answer ✓
    • Now you're wondering whether there are some fix or workaround in order for each callback to have its own closure rather than share the same single 1? [-O<
    • Well, there are some techniques for it. But I'm just gonna post the easiest 1. :-$
    • Use let (or const) in place of var for declaring the iterator variable: for (let i = 0; i < button.length; ++i) {. :)>-
    • W/ keyword let, each loop iteration gets a brand new variable i rather than reusing it. :-bd
    • Meaning each callback is gonna get its own i closure access! \m/
    • Now the full solution for your loop excerpt: :bz

    for (let i = 0; i < buttons.length; ++i)
      buttons[i] = createButton(i).mousePressed(() => print(i));
    
  • This is exceptional. Informative and effective! (and the emoji certainly spice things up too!) The fat arrow, is that ES6? I haven't learned about that yet. Thanks a million!

Sign In or Register to comment.