-
Notifications
You must be signed in to change notification settings - Fork 26
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
fix: handle undefined values in answer lists #2204
Conversation
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.
I have a couple reservations when it comes to implementing in this way, see comments inline - happy to discuss on a call if useful
src/app/shared/utils/utils.ts
Outdated
if (field && value) { | ||
if (["undefined", "NaN", "null", '""'].includes(value)) value = undefined; |
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(blocking)
Do you have any idea how a string "undefined"
"NaN"
or "null"
could be populated? It would be much better to fix at the source, e.g. if there is some sort of getStringParam
parsing these then we should apply the fix there instead. I'm guessing similarly we need a sensible response for NaN
which I'm guessing comes from some parseNumberParam` or similar...
Additionally I'm not sure converting empty string to undefined makes sense. When thinking of answer lists there's sometimes a case where html components may want to use empty string to represent nothing selected in the context of something like a select dropdown.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select
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.
Yeh I don't think this was sensible, I've updated to only convert the string "undefined"
to undefined
. It is supposed to catch precisely the case where the value is undefined
because the answer list is being generated from a data list which may not have a value in the relevant column
src/app/shared/utils/utils.ts
Outdated
// e.g. "image" and "text" are undefined because the list has been generated within a template | ||
const filteredAnswerListItems = answerListItems.filter((item: IAnswerListItem) => { | ||
for (let [key, value] of Object.entries(item)) { | ||
if (key !== "name" && value !== undefined) return true; |
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(blocking)
This logic seems a bit confusing to me, we're running a filter operation but then have an inner for loop which will escape before completion. Might make more sense as 2-step operation, e.g more like
const hadItemData = Object.entries(item).find(([key,value])=>(key !== "name" && value !== undefined)
return hadItemData ? true : false
That being considered, I'm not sure if this makes total sense to implement - surely it's better to let broken images through so that an author can be aware of an authoring mistake instead of just hiding the data away? I'd probably lean more towards providing an authoring option to add a filter function to the specific component, e.g. filter_no_image:true
or ensuring support for runtime filtering, e.g. @data.some_list.filter(item=>item.image!==undefined)
Additionaly we'd still end up with broken images in cases where text is supplied without image with the above filter.
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.
Your suggested logic is definitely clearer, I have refactored accordingly.
In terms of allowing through broken images, a broken image link will still be allowed through with the suggested implementation – an invalid path to an image will still display a broken image link. The image
will only be filtered out if the value is undefined
– which admittedly could be due to an authoring error that the author should be made aware of, but it's not clear to me that displaying a broken image would be necessary in such cases.
Either way, returning to the issue referenced in this PR, we want a way to author an answer list in a generic way where the source data may or may not contain image paths, and in the case where an item does not reference an image, to display no image (and not a broken image link). Filtering on the undefined
values as suggested seems like a satisfactory solution, but I may be missing some associated problems, and there may be other approaches.
Ultimately, I think the best solution may be a way of defining arbitrary data structures, or at least answer lists, directly from data lists, handled at parse-time, in a way that can handle lists of multiple length and containing partial values (as in WIP RFC for a universal data list parser). But I think we want an acceptable solution sooner in order to help with the current authoring requirements.
Just to quickly summarise from the call today
|
…empla teRow util function
I think this is actually quite straightforward: #1967 introduced the I've now added a commit to this PR, which incorporates this logic into a |
Ah - yeah I see now, yeah the answerlist is usually stored in an intermediate local variable which is an array (auto converted by parser for anything with _list in name), but whose elements are formatted string. So when the dynamic variables are replaced they are dropped into something like So what would actually be better would be to process these within the parser to convert the string-array into an object-array. That way when replacing the localVariable it could already be formatted as: [{
"name": "@local.name",
"text": "@local.text"
}] Which when converted should replace the variables (local, data, field or anything else) it should be able to assign the proper value. I think would make sense to merge what's here now to fix the issue in the short term, and then I'll try make a quick follow-up pr/issue to see if possible to update the parser as needed. |
_default: IAnswerListItem[] | ||
): IAnswerListItem[] { | ||
const params = row.parameter_list || {}; | ||
console.log(params[name]); |
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(non-blocking) can remove temp logs
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.
Thanks @jfmcquade
I think looks good to fix the immediate issue (have suggested follow-up in separate comment). I think also makes sense to have the more unified way to extract answer list param so thanks for adding
* (possibly still in string representation) or a data list (hashmap of IAnswerListItems) | ||
*/ | ||
function parseAnswerList(answerList: any) { | ||
if (!answerList) return []; |
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.
nice addition (although shame the git diff isn't showing very cleanly)
I think the rest of the code is the same as you updated previously, so looks good to me
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.
I've created an issue here: #2210
This was actually a log I didn't mean to leave in. If it, or a similar log, would be useful to keep then we should probably add a label like |
Okay, I guess it would be more consistent with the rest of the app to leave it out - and the console would be less cluttered. This does remind me of our discussion that it would be useful for debugging to "see" the values of local variables somehow. Would it be possible/sensible to have logs of this sort visible in the console when the debug-mode is enabled? |
PR Checklist
Description
Handles the case where some values for
text
orimage
within an answer list may be undefined. When authoring an answer list that gets dynamically populated by various data lists, there will sometimes beundefined
values that are complicated to handle at an authoring level (#2166). For example, for a generated answer list of length 4:This PR adds answer list parsing such that:
This fix applies to all components that take
answer_list
parameters:combo_box
,radio_button_grid
andradio_group
. See demos below.Testing
Test the debug_answer_list_partial template (see screenshots below). Also consider testing example_answer_data, which was added in #1967 (the summer of love) to test answer lists coming directly from data lists, to ensure this still functions as expected.
Git Issues
Closes #2166
Screenshots/Videos
Template debug_answer_list_partial:
Data list debug_answer_list_partial_data:
debug_answer_list_partial demo.
Note that in this demo, the
combo_box
andradio_grid
components displays a blank box foroption_3
. This is becauseoption_3
does have a value forimage
in the answer list, and only those items with no value for all other fields besidesname
will be removed from the answer list. In actual applications, answer lists passed to acombo_box
andradio_grid
components would not typically contain any properties besidesname
andtext
(there would be noimage
). If we do want to handle undefined values in the case of an answer list that will be used for bothcombo_box
and, for example,radio_button_grid
components, that can be handled in a follow-up.answer.list.partial.demo.mov