Loading Workflow Data, forceInput and Multiline Text
- Dominant language
- Python
- Stars
- 133k
- Forks
- 15.7k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 155
Description
### Custom Node Testing
- [x] I have tried disabling custom nodes and the issue persists (see [how to disable custom nodes](https://docs.comfy.org/troubleshooting/custom-node-issues#step-1%3A-test-with-all-custom-nodes-disabled) if you need help)
### Expected Behavior
**Descriptions:**
The problem is that when writing a custom extension that adds another widget to the node (for example, my **_Speech And Recognition extension_**: https://github.com/AlekPet/ComfyUI_Custom_Nodes_AlekPet/blob/master/ExtrasNode/js/extras_speech_and_recognition.js), which has a multi-text field and forceInput, it incorrectly loads data from the workflow.
Maybe I somehow incorrectly add the widget to the node, but with two multi-text fields, everything works fine 😄 .
**I made a more simplified version of the verification extension, which uses one checkbox and stores its value.**
https://github.com/user-attachments/assets/66cf7800-ff29-40e4-93d3-236dc9f8c8b4
**_Example python code nodes._**
```py
class TestTextNode:
@ classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": ("STRING", {"default": "", "forceInput":True}),
"words": ("STRING", {"multiline": True, "default": ""}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("STRING",)
CATEGORY = "alekpet-test"
DESCRIPTION = "This node outputs text."
FUNCTION = "ret_text"
def ret_text(self, text="", words=""):
result_text = text * 5
return (result_text,)
class TestTextTwoNode:
@ classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": ("STRING", {"default": "", "forceInput":True}),
"words": ("STRING", {"multiline": True, "default": ""}),
"words2": ("STRING", {"multiline": True, "default": ""}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("STRING",)
CATEGORY = "alekpet-test"
DESCRIPTION = "This node outputs text."
FUNCTION = "ret_text_two"
def ret_text_two(self, text="", words="", words2=""):
result_text = text * 5
return (result_text,)
```
**_Example js code extension._**
```js
import { app } from "../../scripts/app.js";
import { $el } from "../../scripts/ui.js";
const idExt = "alekpet.hello_world";
// -- Extension: Speak text & Recognition speech --
app.registerExtension({
name: idExt,
async beforeRegisterNodeDef(nodeType, nodeData, app) {
// Node Created
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = async function () {
const ret = onNodeCreated
? onNodeCreated.apply(this, arguments)
: undefined;
let nodeIsMultiString = false;
if (nodeData?.input && nodeData?.input?.required) {
for (const inp of Object.keys(nodeData.input.required)) {
if (
nodeData.input.required[inp][1]?.multiline &&
!nodeData.input.required[inp][1]?.forceInput
) {
const type = nodeData.input.required[inp][0];
if (["STRING"].includes(type)) {
nodeIsMultiString = true;
break;
}
}
}
}
if (nodeData?.output) {
for (const out of nodeData.output) {
const isElementTextArea = this?.widgets?.some(
(w) =>
w?.element?.tagName === "TEXTAREA" ||
w?.inputEl?.tagName === "TEXTAREA"
);
if (isElementTextArea && ["STRING"].includes(out)) {
nodeIsMultiString = true;
break;
}
}
}
if (!nodeIsMultiString) return ret;
// Find all widget type customtext
const widgetsTextMulti = this?.widgets?.filter((w) =>
["customtext", "converted-widget"].includes(w.type)
);
const isIncludesSpeech = this?.widgets?.some(
(w) => w.type === "hello_world_type"
);
if (!isIncludesSpeech && widgetsTextMulti?.length) {
widgetsTextMulti.forEach(async (w) => {
const el = $el("input.widget_hello_world_el", { type: "checkbox" });
this.addDOMWidget("widget_hello_world", "hello_world_type", el, {
setValue(v) {
el.checked = v;
},
getValue() {
return !!el.checked;
},
});
});
}
return ret;
};
},
});
```
**Video console.log:**
https://github.com/user-attachments/assets/9866e660-82cb-4a87-9f45-4cf1d23f247c
The entire extension and test users can be found here: [alek_test.zip](https://github.com/user-attachments/files/21387317/alek_test.zip)
And the workflow for testing: [load_data_workflow_forcedinput_one_mtext.json](https://github.com/user-attachments/files/21387238/load_data_workflow_forcedinput_one_mtext.json)
### Actual Behavior
It should load and save normally as with one multi-text field. As with input data that does not have a property in the forceInput field.
### Steps to Reproduce
1. Enable or install an extension that adds a new widget to a multi-text field
2. Add a widget with forceInput and one multi-text field to the workflow
3. Change the values in the fields
4. Switch to another workflow or refresh the page.
5. See the result of loading values.****
### Debug Logs
```powershell
In the onSerialize method if you track all the values are saved correctly.
this.onSerialize = (o)=>{
console.log(o.type, o.widgets_values)
}
Video console.log below in the Expected Behavior
```
### Other
Perhaps it is necessary to somehow process the data when loading, but why does everything work with two or more multi-text fields, but with one the loading of values breaks, reducing the data in the widgets_values array.
Contributor guide
Assessment
This issue has not been assessed yet.