How to create and customize a Function Block with parameters?

2,647 views
Skip to first unread message

pfei...@gmail.com

unread,
Feb 24, 2019, 3:14:26 PM2/24/19
to Blockly
Hi everyone!
I am trying to create and customize a function block with a parameter (pElement). However, although in the block factory helped me defining the statement block, I don't find a way to call and use the parameter that I am requiring inside of it.

Here is the code that I have. Thank you for your collaboration!

Blockly.Blocks['insert_function'] = {
  init: function() {
    this.appendDummyInput()
        .appendField("Define the Function: \"Insert an Element\"")
        .appendField(new Blockly.FieldVariable("element"), "pElement");
    this.appendStatementInput("INSERTED")
        .setCheck("Number");
    this.setColour(15);
    this.setTooltip('');
  }
};

Blockly.JavaScript[''insert_function'] = function(block) {
  var pElement = Blockly.JavaScript.variableDB_.getName(block.getFieldValue('pElement'), Blockly.Variables.NAME_TYPE);
  var statements = Blockly.JavaScript.statementToCode(block, 'INSERTED');
  // TODO: Assemble JavaScript into code variable.
  var code = statements+';\n';
  return code;
};

Amber B

unread,
Feb 25, 2019, 8:58:34 AM2/25/19
to Blockly
Just so I'm clear, have you looked at the blocks in procedures.js in the Blockly project itself? Those should already have function definition blocks similar to what you seem to be trying to accomplish here.

Erik Pasternak

unread,
Feb 25, 2019, 12:27:23 PM2/25/19
to Blockly
Hi There,

I'm not sure I understand what you're trying to do. Are you asking for help using pElement in the generated code or are you creating a function block with a fixed parameter that your users can add blocks in? What's the use case you're trying to solve for?

Cheers,
Erik

pfei...@gmail.com

unread,
Feb 25, 2019, 12:50:58 PM2/25/19
to Blockly
Hi!

Thank you for your response!
What I am trying to do is to offer my users predefined functions. Do you know how can I do that?

Thank you again!

Erik Pasternak

unread,
Feb 25, 2019, 1:10:35 PM2/25/19
to Blockly
Alright, the easiest way since you aren't allowing your users to change the parameters will be to create two blocks. The function definition that you've already made and a caller block. The caller block should have a single value input for the parameter.

From there you can update your function definition block to generate a function:
Blockly.JavaScript['insert_function'] = function(block) {
  var pElement = Blockly.JavaScript.variableDB_.getName(block.getFieldValue('pElement'), Blockly.Variables.NAME_TYPE);
  var statements = Blockly.JavaScript.statementToCode(block, 'INSERTED');
  // TODO: Assemble JavaScript into code variable.
  var code =  'insert_function = function(pElement) {\n' + statements+';\n};
  return code;
};

Then your code generator for the caller block is:
Blockly.JavaScript['insert_caller'] = function(block) {
          var input = Blockly.JavaScript.valueToCode(block, 'PARAM') || '0'; // Defaults to 0
  var code = 'insert_function(' + input + ');';
  return code;
};

You'll also want to do some extra configuration like make it only allow one instance of the definition block and maybe make it start with an undeleteable instance of the definition already on the workspace.

pfei...@gmail.com

unread,
Feb 25, 2019, 4:57:56 PM2/25/19
to Blockly
Thank you!

Do you know if it is possible to use the functions' blocks, already existing in Blockly, but predefining their names as something not editable by the user?

Thank you again,

Coda Highland

unread,
Feb 25, 2019, 5:42:10 PM2/25/19
to blo...@googlegroups.com
I mean at that point you basically just want to make normal custom blocks. Give it a statement input.

/s/ Adam

--
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.
For more options, visit https://groups.google.com/d/optout.

Beka Westberg

unread,
Feb 25, 2019, 6:58:14 PM2/25/19
to Blockly
Hello,

If you really want to use the predefined function blocks you can add the editable="false" tag to a procedure block in XML, and the load it.


Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(
 
'<xml>' +
 
'  <variables>' +
 
'    <variable type="" d="`8;g9~(VS=P]$@DpXo?;">myCustomParamterName</variable>
  '
 </variables>' +
  /
* This is where the important tag is.*/
 
'  <block editable="false" type="procedures_defnoreturn">' +
 
'    <mutation>' +
 
'      <arg name="myCustomParameterName" varid="`8;g9~(VS=P]$@DpXo?;"></arg>' +
 
'    </mutation> ' +
 
'    <field name="NAME">myCustomProcedureName</field>' +
 
'    <comment pinned="false" h="80" w="160">Describe this function...</comment>' +
 
'  </block>' +
 
'</xml>'), myWorkspace);


This will make it so that people can add blocks to the function, but they won't be able to edit the parameters or name. Note1: This doesn't actually force the user to use the parameter, it just makes it exist. Note2: The procedure blocks also already have a defined generator, so if you want to change what code the procedure blocks generate you're going to have to edit the core.

I hope this at least gives you an interesting alternative. Good luck with your problem! It sounds like a tricky one!
Beka

pfei...@unbosque.edu.co

unread,
Feb 28, 2019, 10:39:16 AM2/28/19
to Blockly
Thank you so much Becka!

Yes, I am looking exactly to have predefined procedures. Could you please help me on how to use your same XML but with JavaScript notation?

Thank you again!

Beka Westberg

unread,
Feb 28, 2019, 10:56:33 AM2/28/19
to Blockly
Hello,

You should also be able to define it like this:

var workspaceBlocks = document.getElementById('workspace_blocks');
Blockly.Xml.domToWorkspace(workspaceBlocks , myWorkspace);


<xml id="workspace_blocks">
 
<variables>
   
<variable type="" id="`8;g9~(VS=P]$@DpXo?;">myCustomParamterName</variable>
  </
variables>

 
<block editable="false" type="procedures_defnoreturn">

   
<mutation>

     
<arg name="myCustomParameterName" varid="`8;g9~(VS=P]$@DpXo?;"></arg>

   
</mutation>

    <field name="NAME">myCustomProcedureName</
field>

   
<comment pinned="false" h="80" w="160">Describe this function...</comment>

 
</block>
</
xml>


But as far as I know there's no way to convert it to pure javascript.

I hope that helps! If you have any other questions please reply!
Beka

Coda Highland

unread,
Feb 28, 2019, 11:37:03 AM2/28/19
to blo...@googlegroups.com
You can also use Blockly.Xml.textToDom with an XML string instead of putting the XML in your HTML page. This has the advantage of being able to synthesize the XML in Javascript code, which means you can change up the parameters and IDs and such dynamically.

You can also use Blockly.Xml.domToBlock or Blockly.Xml.appendDomToWorkspace instead of domToWorkspace, if you don't want to clear the workspace when you add the new block.

/s/ Adam

--

pfei...@gmail.com

unread,
Feb 28, 2019, 8:04:29 PM2/28/19
to Blockly
Hello guys! Thank you so much!

Could you please explain to me how to make that predefined procedure block available in my blocks' menu?
I want to offer my users the possibility of selecting or not this block for their use.

Thank you!

Beka Westberg

unread,
Feb 28, 2019, 8:55:34 PM2/28/19
to Blockly
Hello,

What have you tried so far? Have you checked out this page? Give it a shot, and if you have trouble please reply with what you did, and what didn't work. Then I'd be happy to help :D

Good luck!
Beka

pfei...@unbosque.edu.co

unread,
Mar 8, 2019, 9:23:14 AM3/8/19
to Blockly
i everyone,

For some reason, when using predefined procedures blocks, the input arguments are not getting the value selected on the Canvas, but the "name" of the arguments instead.

The XML code I used for the predefined procedure block is:

                                 <category name="Functions on Items">
<block editable="false" type="procedures_defnoreturn">
<field name="NAME">insertElementToItem</field>
<mutation>
  <arg name="item" varid="currentItem"></arg>
      <arg name="element" varid="newElement"></arg>
    </mutation>
     <comment pinned="false" h="80" w="160">Describe this function...</comment>
</block>
</category>

The code used to get both input arguments is:
                  var value_item = Blockly.JavaScript.valueToCode(block, 'item', Blockly.JavaScript.ORDER_ATOMIC);
  var value_element = Blockly.JavaScript.valueToCode(block, 'element', Blockly.JavaScript.ORDER_ATOMIC);

So, what is happening is that in both, value_item and value_element, when I alert the received input it is "item" for value_item and "element" for value_element. 
I simply don't know why and how to fix this. Could you please help me?

Thank you and I will be waiting for your response.

Best regards,

Erik Pasternak

unread,
Mar 8, 2019, 4:21:00 PM3/8/19
to Blockly
I'm pretty sure that's working as intended. The generated code for a variable is its display name, not its id. The display name gets altered if it's not legal or it would replace another variable, but otherwise is left as is. This is so that the generated code is easier for users to match with the block code.
Reply all
Reply to author
Forward
0 new messages