简体   繁体   English

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

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

I've been trying to make a custom block in the Blockly workspace that changes the options in drop-down fields based on the selection of a previous drop-down field in the same block.我一直在尝试在 Blockly 工作区中创建一个自定义块,该块根据对同一块中前一个下拉字段的选择来更改下拉字段中的选项。 About the block:-关于区块:-

  1. There are three dropdown fields共有三个下拉字段
  2. All are populated dynamically using Blockly.Extensions所有都是使用 Blockly.Extensions 动态填充的
  3. All codes are present below所有代码都在下面

I've implemented an 'onchange' function to the blockly initialization that gets the change data through the 'event' variable and responds accordingly.我已经实现了一个'onchange' function 到通过'event'变量获取更改数据并相应响应的块初始化。 I'm having problems trying to update the changing drop-down fields.我在尝试更新不断变化的下拉字段时遇到问题。 Please assist.请协助。

Code代码

// 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
        }
    }
}

Here is a snapshot of the block that is generated:这是生成的块的快照: 在此处输入图像描述

tldr; tldr; Update options of a drop-down field in a block when the selected option of another drop-down is changed.当另一个下拉列表的选定选项更改时,更新块中下拉字段的选项。

Thanks, Utkarsh谢谢, 乌特卡什

Thanks to @beka from Google Blockly groups at https://groups.google.com/g/blockly .感谢来自https://groups.google.com/g/blockly的 Google Blockly 组的@beka。

The main problem here was conceptual.这里的主要问题是概念上的。 A block has一个块有

  1. inputs: field rows that can have anything like value blocks (puzzle piece input) or statement blocks (lego input)输入:字段行可以有任何像值块(拼图输入)或语句块(乐高输入)
  2. fields: like from HTML.字段:例如来自 HTML。 these can be text boxes, drop-downs, images, etc.这些可以是文本框、下拉列表、图像等。

Both the input and the field can have names.输入和字段都可以有名称。 And it is good practice to name them differently.以不同的方式命名它们是一种很好的做法。

As seen in my extensions, I'd taken my input this.getInput('columnInput') and appended a field .appendField with the same name.正如在我的扩展中看到的那样,我接受了我的输入this.getInput('columnInput')并附加了一个具有相同名称的字段.appendField Due to this, the input had a field with the same name.因此,输入具有相同名称的字段。

Here are the corrections:以下是更正:

  1. to the extensions:到扩展:

    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. to the functions updating all the dropdowns inside the block initialization onchange到更新块初始化 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

And ofcourse, if you personally face any issue while this.getInput('').removeField('') , log the input object console.log(this.getInput('')) and assess.当然,如果您在this.getInput('').removeField('')期间遇到任何问题,请记录输入 object console.log(this.getInput(''))并评估。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM