-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Cache dynamic dropdown options #3036
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cache dynamic dropdown options #3036
Conversation
|
@BeksOmega FYI. I'm also a little surprised that we don't support an empty options list, but that can be dealt with in a different change. |
BeksOmega
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good! I'm glad you went back and found this one.
core/field_dropdown.js
Outdated
| tuple); | ||
| } | ||
| } | ||
| if (!options.length) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Uncaught errors are the worst.
| * @type {Array.<!Array.<string>>} | ||
| * @private | ||
| */ | ||
| this.generatedOptions_ = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you look into having this be a map/dictionary? I think there are some loops that could be elliminated that way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would the key of this map be? If it's the value, it means you can't have multiple options with the same value, label is the same. I don't think we set that restrictions right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would the key of this map be?
It would be keyed by value. This is what the dropdown currently uses, it's just inefficient and uses for-loops instead of a map.
We may not currently throw errors, but the language-neutral keys of your dropdown have to be unique, otherwise your dropdown breaks:
Steps to reproduce
- Add the following block definition to the playground.
{
"type": "test_dropdowns_same_value",
"message0": "same value %1",
"args0": [
{
"type": "field_dropdown",
"name": "FIELDNAME",
"options": [
[ "first item", "ITEM1" ],
[ "second item", "ITEM2" ],
[ "third item", "ITEM2" ],
[ "fourth item", "ITEM2" ],
[ "fifth item", "ITEM2" ],
]
}
],
"style": "fields_dropdowns"
}
- Add the block to the workspace.
- Use the dropdown.
- Observe the bad behavior.
If we were to switch it to a map we could definitely get rid of the loop in doClassValidation_. We could also probably get rid of the selectedIndex_ property and just use the value instead, elliminating the loop in doValueUpdate_.
| }) | ||
| }; | ||
|
|
||
| Blockly.Blocks['test_dropdowns_dynamic_random'] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fun hehe.
Do you have a use case in mind? I think that's it generally good to oppose that behavior so that you avoid dealing with nulls in code generation. I'm having trouble thinking of a situation where the limitation can't be designed around (e.g. variables), but I could be missing something. |
I mentioned to @samelhusseini that I think our APIs made this easy to do with dynamic dropdown functions. Looking at our existing code, an empty options list is allowed by validateOptions_ but then we assume it's non-empty a few lines later in the constructor. It's probably better if we handle an empty list in one spot instead of expecting every option generator to check for it. |
I agree that it is a bit annoying to have to design around this limitation (as with most limitations hehe) but I think allowing empty lists and nulls would actually end up creating /more/ work (for us, and outside developers) in the longrun. Firstly, if outside developers don't handle this at option-generation-time they'll end up having to handle it at code-generation-time. That is a much trickier spot to find bugs. I think we're actually helping them by notifying them before it gets to that point. Secondly, allowing empty lists and nulls creates a lot more work for us, because now we have to check for that. We'd have to start checking for empty lists all over the dropdown field, and special case them. For example:
We'd also no longer be able to confidently call Two other small points:
In Conclusion: It saves outside developers the headache in the long run. It makes Blockly less fragile and more elegant. And I can't think of a usecase for empty lists (at least one that doesn't have a better solution). |
|
@BeksOmega good points, especially about it never working with an empty list. If @samelhusseini agrees then I'm okay with requiring a non-empty list of options and updating validateOptions_ to explicitly check for an empty list and throw a meaningful error in that case. |
|
I agree with the points made here. This PR adds a check in |
core/field_dropdown.js
Outdated
| * cached options or to re-generate them. | ||
| * @return {!Array.<!Array>} A non-empty array of option tuples: | ||
| * (human-readable text or image, language-neutral name). | ||
| * @throws If generated options are incorrectly structured. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Could we add the type here? @throws {Type}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.

The basics
The details
Resolves
#2493
#2926
Proposed Changes
Only generate options during inialization (as we need the first tuple) and when a use clicks on the field to open it. (ie: when the editor is shown / widget is created).
Reason for Changes
Be more efficient about calling a dynamic dropdown function and not break in places where we expect certain options to be available.
Test Coverage
Tested the playground, and added a new test dropdown block that returns a random number of items every time the generate method is called.
Tested on:
Documentation
Additional Information