问题描述
我一直在尝试在 Blockly 工作区中创建一个自定义块,该块根据同一块中上一个下拉字段的选择来更改下拉字段中的选项。 关于区块:-
- 共有三个下拉字段
- 全部使用 Blockly.Extensions 动态填充
- 所有代码都在下面
我已经为块初始化实现了一个 '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"
},"name": "column_input1","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'],'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; 当另一个下拉列表的选定选项发生更改时,更新块中下拉字段的选项。
谢谢, 乌特卡什
解决方法
感谢来自 https://groups.google.com/g/blockly 的 Google Blockly 群组的 @beka。
这里的主要问题是概念上的。一个区块有
- 输入:字段行,可以有任何值块(拼图输入)或语句块(乐高输入)
- 字段:就像来自 HTML。这些可以是文本框、下拉菜单、图片等。
输入和字段都可以有名称。最好以不同的方式命名它们。
正如在我的扩展中看到的那样,我接受了我的输入 1
并附加了一个具有相同名称的字段 this.getInput('columnInput')
。因此,输入有一个同名的字段。
以下是更正:
- 扩展名:
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 })
- 更新块初始化中的所有下拉列表的函数
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'],'column_input_field') // updated the field name different from input name
当然,如果您个人在 .appendField
期间遇到任何问题,请记录输入对象 this.getInput('').removeField('')
并进行评估。