Custom block to return a random string not working (newbie...)

159 views
Skip to first unread message

Elena

unread,
Oct 2, 2023, 1:30:28 PM10/2/23
to Blockly
Hi everyone,
I created a block that returns a random string, but the problem is that I am not able to print it, here is my code:

Blockly.Blocks['joke'] = {
init: function () {
this.appendDummyInput()
.appendField("Tell a random joke");
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setOutput(true, 'String');
this.setColour(290);
this.setTooltip("Tooltip text");
this.setHelpUrl("");
}
};

javascript.javascriptGenerator.forBlock['joke'] = function (block) {
let jokes = ["joke 1", "joke 2", "joke 3", "joke 4", "joke 5", "joke 6", "joke 7", "joke 8", "joke 9", "joke 10"];
let random = Math.floor(Math.random() * jokes.length);
let code = "return " + jokes[random] + "";
return code;
};
It returns the random string but not inside the alert function :(

jokeblock.JPG

what am I doing wrong? I just started with Blockly and I am still figuring it all out. 

Thank you !

Elena

unread,
Oct 2, 2023, 2:40:50 PM10/2/23
to Blockly
Updated code (still not working):

Blockly.Blocks['joke'] = {
    init: function () {
      this.appendDummyInput()
        .appendField("Tell a random joke");
      // this.setPreviousStatement(false, null);
      // this.setNextStatement(false, null);
      this.setOutput(true, 'String');
      this.setColour(290);
      this.setTooltip("Tooltip text");
      this.setHelpUrl("");
    }
  };
javascript.javascriptGenerator.forBlock['joke'] = function (block) {
    let jokes = ["joke 1", "joke 2", "joke 3", "joke 4", "joke 5", "joke 6", "joke 7", "joke 8", "joke 9", "joke 10"];
    let random = Math.floor(Math.random() * jokes.length);
    let code = "'" + jokes[random] + "'";
    return code;
  };


jokeblock2.JPG

Mark Friedman

unread,
Oct 2, 2023, 5:30:12 PM10/2/23
to blo...@googlegroups.com
Elena,

  I think that the main issue with the code you posted is that the code generator function for a block that returns a value (i.e. has setOutput(true, ...)) needs to return an array of two items, i.e. the code and the preference.  See here for more details.

  Another potential issue that you might be interested in is that with the posted code is that the particular random joke that is returned for each "Tell a random joke" block in the program is going to get set at the time that the code is generated, not the time that the code is run.  If you want the randomness to occur at the time that the code is run, you will want to put your randomization inside the string that gets generated rather than in the code that is run by the code generator function.

  Hope this helps.

-Mark


--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/blockly/a847062d-f03f-44dc-936c-24a17e3031dfn%40googlegroups.com.

Elena

unread,
Oct 3, 2023, 5:01:18 AM10/3/23
to Blockly
Hi Mark,
thank you for your response!

I tried several orders from this page:
jokeblock3.JPG
but none of them are working, since I am just returning a string I thought that ATOMIC or NULL would be a good choice but now my block doesn't return anything:

Blockly.Blocks['joke'] = {
    init: function () {
      this.appendDummyInput()
        .appendField("Tell a random joke");
      // this.setPreviousStatement(true, null);
      // this.setNextStatement(true, null);
      this.setOutput(true, 'String');
      this.setColour(290);
      this.setTooltip("Tooltip text");
      this.setHelpUrl("");
    }
  };

  javascript.javascriptGenerator.forBlock['joke'] = function (block) {
    let jokes = ["joke 1", "joke 2", "joke 3", "joke 4", "joke 5", "joke 6", "joke 7", "joke 8", "joke 9", "joke 10"];
    let random = Math.floor(Math.random() * jokes.length);
    let code = "'" + jokes[random] + "'";
    return [code, Order.ATOMIC];
  };

As for the randomness you are right, I will tackle this problem too and let you know!

Thanks 
Elena

Elena

unread,
Oct 3, 2023, 1:17:26 PM10/3/23
to Blockly
I found the problem (but not the solution):

at the top of my code I should have something like this:

import {Order} from 'blockly/javascript';

but the problem is I am not using imports, here is a link to complete code https://jsfiddle.net/elenat82/v1z5qns9/2/

What should I do?

Thanks
Elena

Mark Friedman

unread,
Oct 3, 2023, 1:39:21 PM10/3/23
to blo...@googlegroups.com
The clue for your solution is to realize that Order and javascriptGenerator are both exported in the same way, which you can see from the example given in the doc page for code generation of values (here):
import {javascriptGenerator, Order} from 'blockly/javascript';
So, despite not using import, the idea is that you can access Order ithe same way that you are accessing javascriptGenerator in your code, i.e. as javascript.Order.

-Mark


Elena

unread,
Oct 3, 2023, 2:03:55 PM10/3/23
to Blockly
I got it!!!!

javascript.javascriptGenerator.forBlock['joke'] = function (block) {
    let code = "let jokes = ['joke 1', 'joke 2', 'joke 3', 'joke 4', 'joke 5', 'joke 6', 'joke 7', 'joke 8', 'joke 9', 'joke 10']; return jokes[Math.floor(Math.random() * jokes.length)]";
    return [code, javascript.Order.ATOMIC];
  };


I think I also solved the randomness problem, but I don't like the fact that the jokes are hard-coded, is it possible to create a block  where the user can enter their jokes and the output of the new block serves as input for this one?
If you think it's possible I will ty to come up with something.

Thank you
Elena



Elena

unread,
Oct 3, 2023, 2:31:29 PM10/3/23
to Blockly
Something like this, so that the Tell a random joke block can output a random element from whatever list you feed.
As for the list I think that it's better to have a collection of single jokes so that the user can input how many jokes they want.

Blockly.Blocks['singlejoke'] = {
    init: function() {
      this.appendDummyInput()
          .appendField("Insert your joke")
          .appendField(new Blockly.FieldTextInput("text of default joke"), "singlejoke");
      this.setInputsInline(false);
      this.setOutput(true, "String");
      this.setColour(290);
   this.setTooltip("Tooltip text for the singlejoke");
    }
  };

  javascript.javascriptGenerator.forBlock['singlejoke'] = function(block, generator) {
    var text_singlejoke = block.getFieldValue('singlejoke');
    console.log('text_singlejoke: ', text_singlejoke);
    // TODO: Assemble javascript into code variable.
    var code = "return " + text_singlejoke;
    // TODO: Change ORDER_NONE to the correct strength.
    return [code, javascript.Order.ATOMIC];
  };


But how can I make my first block accept inputs?

Thanks
Elena


ewpa...@gmail.com

unread,
Oct 4, 2023, 2:08:21 PM10/4/23
to Blockly
Hi Elena,

It looks like you are using appendDummyInput, which is an input type that doesn't accept blocks. If you want to be able to plug blocks into your new block, you should use either appendValueInput(NAME) or appendStatementInput(NAME) (most likely the former), where NAME is a string that names the input so that you can access its connected block in the code generator.

Cheers,
Evan

Elena

unread,
Oct 4, 2023, 4:52:35 PM10/4/23
to Blockly
Hi Evan,

thank you for your help!

I created a block that accepts a list and returns a random element from the list, here is my updated jsiddle: https://jsfiddle.net/elenat82/v1z5qns9/11/

Blockly.Blocks['return_random_from_list'] = {
    init: function () {
      this.appendDummyInput()
        .appendField("Add a list");
      this.appendValueInput("list")
        .setCheck(null);
      this.setInputsInline(false);
      this.setOutput(true, null);
      this.setColour(230);
      this.setTooltip("This block returns a random element from the input list");
    }
  };

  javascript.javascriptGenerator.forBlock['return_random_from_list'] = function (block, generator) {
    let value_list = generator.valueToCode(block, 'list', javascript.Order.ATOMIC);
    let code = "";
    if (value_list) {
      code = "let values = " + value_list + "; return values[Math.floor(Math.random() * values.length)] ";
    }
    console.log('code for the return_random_from_list block: ', code);
    return [code, javascript.Order.ORDER_NONE];
  };
And you use it like this:

jokeblock4.JPG

Tomorrow I will try to come up with something to enrich my block!

Thanks
Elena

Elena

unread,
Oct 6, 2023, 11:58:42 AM10/6/23
to Blockly
Hi Mark and Evan,

just wanted to let you know that thanks to your help I think I have reached my goal:

now I have a block that accepts a list and returns a random element from that list, you can insert your jokes or use one of the three default hidden jokes.
I also added a block that calls a free API to return the weather forecast for the location you insert in the block field.
What do you guys think?

Here is my updated jsfiddle  https://jsfiddle.net/elenat82/v1z5qns9/21/ and the blocks in action:

jokeblock5.JPG

jokeblock6.JPG

Thanks
Elena

Mark Friedman

unread,
Oct 6, 2023, 2:04:05 PM10/6/23
to blo...@googlegroups.com
That's great to hear, Elena!

-Mark


Reply all
Reply to author
Forward
0 new messages