How can I use input text value in blockly to set a dynamic dropdown?

715 views
Skip to first unread message

Víctor Moreno

unread,
Mar 24, 2021, 6:31:13 AM3/24/21
to Blockly

I want to build a block that searches in a list the input text value ad display the results in the dropdown dynamically (using blockly).

This is what I am building but I am not able to get and use the text input value:


{
        "type": "search",
        "message0": "%1 %2",
        "args0": [
          {
            "type": "field_input",
            "name": "input1",
            "text": "whatever",
          },
          {
            "type": "input_dummy",
            "name": "INPUT"
          }
        ],
      "extensions": ["dynamic_menu_extension"],
      },
    
      Blockly.Extensions.register('dynamic_menu_extension',
      function() {
        this.getInput('INPUT')
          .appendField(new Blockly.FieldDropdown(
            function() {
              var options = [];
              Blockly.JavaScript['search'] = function(block) {
                var searchVal = block.getFieldValue('input1');
                return searchVal;}
              for (var i=0 ; i < list.length ; i++)
            {
                 if (list[i] == searchVal) {
                    options.push([list[i],list[i]]);
                }
            }
              return options;
            }), 'whatever1');
      });

Beka Westberg

unread,
Mar 24, 2021, 11:07:44 AM3/24/21
to blo...@googlegroups.com
Hello,

It looks like you have your relevant code wrapped inside of a function, which is not being called.
```
Blockly.Extensions.register('dynamic_menu_extension',
      function() {
        this.getInput('INPUT')
          .appendField(new Blockly.FieldDropdown(
            function() {
              var options = [];
              // This function is not being called anywhere

              Blockly.JavaScript['search'] = function(block) {
                var searchVal = block.getFieldValue('input1');
                return searchVal;
              }
              for (var i=0 ; i < list.length ; i++) {
                // So here searchVal is undefined.

                if (list[i] == searchVal) {
                    options.push([list[i],list[i]]);
                }
              }
              return options;
            }), 'whatever1');
      });
```

The Blockly.JavaScript namespace is used for code generation, so this is not the proper place/way to assign to it. I think what you want to do instead is something like this:
```
Blockly.Extensions.register('dynamic_menu_extension',
      function() {
        this.getInput('INPUT')
          .appendField(new Blockly.FieldDropdown(
            function() {
              var options = [];
              // Function has been removed, and we're just getting the value.

              var searchVal = block.getFieldValue('input1');
              for (var i=0 ; i < list.length ; i++) {
                if (list[i] == searchVal) {
                    options.push([list[i],list[i]]);
                }
              }
              return options;
            }), 'whatever1');
      });
```

The second problem I see is that you're using a `list` variable, but `list` has not been defined in this scope. Assuming that a `list` property is defined on your block, you probably meant something like:
```
Blockly.Extensions.register('dynamic_menu_extension',
      function() {
        this.getInput('INPUT')
          .appendField(new Blockly.FieldDropdown(
            function() {
              var options = [];
              // block is not in scope either.
              // Use `this` (which is the dropdown field) to access the block.
              var block = this.getSourceBlock();

              var searchVal = block.getFieldValue('input1');
              for (var i = 0; i < block.list.length; i++) {
                if (block.list[i] == searchVal) {
                    options.push([block.list[i], block.list[i]]);

                }
              }
              return options;
            }), 'whatever1');
      });
```

There may be other issues you'll have to debug, but those are the ones that stood out to me =)

I hope that helps! If you have any further questions please reply :D
--Beka

--
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/d44e83f3-22a8-4a88-9357-2b9193e139c3n%40googlegroups.com.

Víctor Moreno

unread,
Mar 24, 2021, 11:34:20 AM3/24/21
to Blockly
Hi Beka, thanks so much for your reply.  

After posting this question I tried exactly what you proposed and I keep getting this error: TypeError: null is not an object (evaluating 'block.getFieldValue')e

Víctor Moreno

unread,
Mar 25, 2021, 5:00:24 AM3/25/21
to Blockly
I think the problem is in  var block = this.getSourceBlock();      since it is not finding the source block. 

If anyone could help me with that it would be much appreciated.

Beka Westberg

unread,
Mar 25, 2021, 11:37:12 AM3/25/21
to blo...@googlegroups.com
Hmm that's odd, the menu generator is called in the scope of the field (as you can see from the dropdown field source). So it should be able to call the getSourceBlock to get the source block.

Given that, I think there are two possibilities for what's going on:
1) You're running a version of Blockly where getSourceBlock doesn't exist. But I think this is unlikely based on the error message.
2) The field hasn't actually been "attached" to the block the first time setValue is called. In this case the easiest thing to do is return a default list of options based on the default value of your text input. This will fix itself when the user first opens the dropdown, or a stored value gets deserialized from XML.

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

Message has been deleted

Víctor Moreno

unread,
Mar 25, 2021, 12:29:46 PM3/25/21
to Blockly
Thanks again, Beka.

The first option cannot be, since I updated Blockly this morning in order to make sure it wasn´t a version issue.

The second option makes so much sense to me. I am trying to apply but I do not know how to do it, could you help me out with that?

Víctor Moreno

unread,
Mar 26, 2021, 4:15:08 AM3/26/21
to Blockly
I think the key of this problem is getting the source block first. Since it is returning null when I do:   console.log(block)

Beka Westberg

unread,
Mar 26, 2021, 10:20:56 AM3/26/21
to blo...@googlegroups.com
Hello,

So just to restate, you want to create a block where a text input field limits the possible options in a dropdown field. The issue is that when the dropdown field is first being constructed, it doesn't have access to the block or text input field because it hasn't been "attached" yet. I think that the best way to deal with this is to handle this is to have a default "backup" search val, that matches the default value of your text input field, the case that it cannot be accessed.

This code could look something like this:
```
Blockly.Extensions.register('dynamic_menu_extension',
      function() {
        this.getInput('INPUT')
          .appendField(new Blockly.FieldDropdown(
            function() {
              var options = [];
              // Change to match the default value of your text input field.
              var searchVal = "some_default_value";

              var block = this.getSourceBlock();
              if (block) {
                searchVal = block.getFieldValue('input1');
              }  // Else the value will just be the default value.

              for (var i = 0; i < list.length; i++) {
                // Now since the block may not always be available, you
                // you shouldn't store the list on the block. Here I've just
                // made the list global again.

                if (list[i] == searchVal) {
                    options.push([list[i], list[i]]);


                }
              }
              return options;
            }), 'whatever1');
      });
```

I hope that helps! If you have any further questions please reply!
--Beka
Message has been deleted
Message has been deleted

Víctor Moreno

unread,
Mar 26, 2021, 11:59:14 AM3/26/21
to Blockly
Hi, Beka. Yes, the idea is to build a block that allows users to type what they want to search in the list to select it in the dropdown.

I implemented the code you wrote but now I get this error the first time I try to pick the block: 

//
core.js:6162 ERROR TypeError: FieldDropdown options must not be an empty array.
//

After that first time I keep getting this: 

//
Tried to start the same gesture twice.
Trying to end a gesture recursively.
//

I am not able to use the block and take it to the workspace but it does work if I delete this part from the code: 
//

if (block) {
                searchVal = block.getFieldValue('input1');
              } 

//

Thank you so much.
Reply all
Reply to author
Forward
0 new messages