Blockly:根据对 inputDummy 下拉字段的选择更新其他 inputDummy 下拉字段

Blockly: Update other inputDummy dropdown fields based on selection of a inputDummy dropdown field

我一直在尝试在 Blockly 工作区中创建一个自定义块,该块会根据同一块中先前下拉字段的选择来更改下拉字段中的选项。 关于区块:-

  1. 有三个下拉字段
  2. 全部使用 Blockly.Extensions
  3. 动态填充
  4. 所有代码都在下面

我已经为块初始化实现了一个 'onchange' 函数,它通过 'event' 变量获取更改数据并做出相应的响应。我在尝试更新不断变化的下拉字段时遇到问题。请协助。

代码

// the block JSON declaration variable
var updateTableData = {
    "type": "al_update_table_data",
    "message0": "Update in table %1 where column %2 is %3 set value for column %4 to %5",
    "args0": [
        {
            "type": "input_dummy",
            "name": "table_input",
        },
        {
            "type": "input_dummy",
            "name": "column_input",
        },
        {
            "type": "input_value",
            "name": "get_value"
        },
        {
            "type": "input_dummy",
            "name": "column_input1",
        },
        {
            "type": "input_value",
            "name": "set_value"
        }
    ],
    "inputsInline": false,
    "previousStatement": null,
    "nextStatement": null,
    "fieldRow": false,
    "colour": 90,
    "tooltip": "Update value in a table",
    "helpUrl": "",
    "extensions": ["get_tables", "get_column", "get_column1"],
}
// the blockly extensions
// get list of tables and populate the 'table_input' drop-down field
Blockly.Extensions.register('get_tables', function () {
    this.getInput("table_input")
        .appendField(new Blockly.FieldDropdown(
            function () {
                let options = []
                let tables = JSON.parse(localStorage.getItem('applab_myTables'))
                tables.map(t => options.push([t.name, t.id]))
                return options
            }
        ), "table_input")
})

// get list of columns from the first table and populate the 'column_input' drop-down field
Blockly.Extensions.register('get_column', function () {
    this.getInput('column_input')
        .appendField(new Blockly.FieldDropdown(
            function () {
                let options = []
                let table = JSON.parse(localStorage.getItem('applab_myTables'))[0]
                Object.keys(table['columnData']).filter(cId => table['columnOrder'].includes(cId)).map(cId => options.push([table['columnData'][cId]['name'], cId]))
                return options
            }
        ), 'column_input')
})

// get list of columns from the first table, remove the column value already selected in 'column_input' and populate the 'column_input1' drop-down field
Blockly.Extensions.register('get_column1', function () {
    var selectedColumn = this.getFieldValue('column_input')
    this.getInput('column_input1')
        .appendField(new Blockly.FieldDropdown(
            function () {
                let options = []
                let table = JSON.parse(localStorage.getItem('applab_myTables'))[0]
                Object.keys(table['columnData']).filter(cId => table['columnOrder'].includes(cId)).filter(cId => cId !== selectedColumn).map(cId => options.push([table['columnData'][cId]['name'], cId]))
                return options
            }
        ), 'column_input1')
})
// Comments with 7 slashes (///////) are my commentary on the issues, errors and outputs that I get
// blockly block initialization
Blockly.Blocks['al_update_table_data'] = {
    init: function () {
        this.jsonInit(updateTableData)
    },
    onchange: function (event) {
        // console.log(event.type)
        var table_id = this.getFieldValue('table_input')
        var selectedcolumn = this.getFieldValue('column_input')
        var otherColumn = this.getFieldValue('column_input1')
        if (event.blockId === this.id) {
            if (event.type === Blockly.Events.BLOCK_CHANGE) {
                // console.log('name of changed field', event.name)
                // console.log('old value', event.oldValue)
                // console.log('new value', event.newValue)
                if (event.name === 'table_input') { 
                    // change in selected table, update column_input and column_input1
                } else if (event.name === 'column_input') {
                    // change in selected column, update column_input1
                    /////// I tried to removeField which did remove the field, but also the label on the same field row. But when I tried to getInput, I get the error: 'column_input1' input doesn't exist
                    // this.removeField('column_input1', true)
                    /////// I tried to removeInput as well, which too removed the field, but also the label on the same field row. And when I tried to getInput, I again get the error: 'column_input1' input doesn't exist
                    // this.removeInput('column_input1')
                    /////// This functions runs fine when I don't remove any input or field. But it keeps adding new drop-downs next to existing ones with new options
                    this.getInput('column_input1')
                        /////// I tried this to use removeField after getInput as well. But it shows the error: this.getInput().removeField() is not a function
                        // .removeField('column_input1')
                        .appendField(new Blockly.FieldDropdown(
                            function () {
                                let options = []
                                let table = JSON.parse(localStorage.getItem('applab_myTables')).find(table => table.id === table_id)
                                Object.keys(table['columnData']).filter(cId => table['columnOrder'].includes(cId)).filter(cId => cId !== event.newValue).map(cId => options.push([table['columnData'][cId]['name'], cId]))
                                return options
                            }
                        ), 'column_input1')
                }
            }
        }
        if (event.type === Blockly.Events.FINISHED_LOADING) {
            // workspace finished loading, update column_input and column_input1 based on selected table
        }
    }
}

这是生成的块的快照:

tldr; 当另一个下拉列表的选定选项发生更改时,更新块中下拉字段的选项。

谢谢, 乌特卡什

感谢来自 Google Blockly groups at https://groups.google.com/g/blockly/c/Vh_zPLrqjdw/m/TWHehaQ1AgAJ 的 @beka。

这里的主要问题是概念上的。一个区块有

  1. 输入:可以包含值块(拼图输入)或语句块(乐高输入)之类的字段行
  2. 字段:类似于 HTML。这些可以是文本框、下拉菜单、图像等。

输入和字段都可以有名称。最好以不同的方式命名它们。

正如在我的扩展中看到的那样,我接受了我的输入 this.getInput('columnInput') 并附加了一个具有相同名称的字段 .appendField。因此,输入有一个同名的字段。

更正如下:

  1. 扩展:

    Blockly.Extensions.register('get_column', function () {
    this.getInput('column_input')
        .appendField(new Blockly.FieldDropdown(
            function () {
                let options = []
                let table = JSON.parse(localStorage.getItem('applab_myTables'))[0]
                Object.keys(table['columnData']).filter(cId => table['columnOrder'].includes(cId)).map(cId => options.push([table['columnData'][cId]['name'], cId]))
                return options
            }
        ), 'column_input_field') // updated the field name different from input name
    })

  1. 更新块初始化 onchange 中所有下拉列表的函数

    this.getInput('column_input').removeField('column_input_field') // first removed the field
    // and then, append a new field with the new options
    this.getInput('column_input')
        .appendField(new Blockly.FieldDropdown(
            function () {
                let options = []
                let table = JSON.parse(localStorage.getItem('applab_myTables')).find(table => table.id === event.newValue)
                Object.keys(table['columnData']).filter(cId => table['columnOrder'].includes(cId)).map(cId => options.push([table['columnData'][cId]['name'], cId]))
                return options
            }
        ), 'column_input_field') // updated the field name different from input name

当然,如果您在 this.getInput('').removeField('') 期间遇到任何问题,请记录输入对象 console.log(this.getInput('')) 并进行评估。