The problem#
Google Forms is a tool that allows for easily setting up simple structured data entry. But it's designed to make it easy to analyze a lot of data that has been entered, not to view a single entry. There is a view to show individual entries, but it's very cluttered due to including all of the options that were not selected as well as those that were selected. A display that showed only the entries that were selected could be used as a quick and dirty way to make a form letter-like website.
To make this problem harder, the solution has to run on iPad, a platform not exactly known for its user programmability.
The solution#
Bookmark this link: hide unselected items in Google Form. Then select that bookmark when on the appropriate Google Forms page. Note that in addition to hiding unselected entries, if the entry that is not select has a value of "Yes", then its entire section will be hidden. If you don't want that behavior, bookmark this variant of the script instead.
The details#
Customizing webpages#
Let's back up a bit.
The web is an interesting platform because most pages are the combination of multiple files that don't have to directly reference each other to work together. This means that users can change the way a web page look for them by defining their own user style. We could use user styles to inject some CSS that would tell the browser to hide the elements that we don't want to see. Similarly, instead of using CSS, we could also write a short JavaScript snippet that would run as a user script to hide those elements.
Unfortunately, both of those options require web browser extensions
which are not available on mobile browsers, so they are not an
appropriate solution for running on an iPad. Luckily, there's a
workaround: bookmarklets. Bookmarklets are JavaScript
programs stored in bookmarks using the javascript:
URI scheme. When
the bookmark is selected, instead of going to a page, it executes the
JavaScript program with the current page's variables available to
it. They're not as powerful as user scripts because they have to be
activated manually, but they can accomplish many of the same tasks.
Writing the script#
That answers how to run our custom JavaScript, but not how I came up with that specific script.
I knew I wanted to hide a set of elements on the page, so the script would look something like
document.querySelectorAll(selector)
.forEach(el => el.style.display = 'none');
which just leaves determining the right value for selector
.
Most modern desktop browsers have an "Inspect" feature where you can right-click on an element and it will bring up the HTML of that element in context. Additionally, when hovering over parts of the HTML, it will highlight which part of the page it corresponds to. Using that, it's fairly straightforward to identify which HTML element is the one we want to hide.
As Google Forms isn't trying to obfuscate what the elements are for,
their class
names are straightforward: disabled items have the
isDisabled
class, checked items have the isChecked
class (well,
strangely, so do disabled items), so with a little experimentation, we
can see that the CSS selector .isDisabled:not(.isChecked)
selects the
disabled items which are not checked.
Additionally, the form I was doing this for had some sections that
were "Yes"/"No" choices instead of multiple-choice, so selecting
"No" meant the whole section should be hidden. I accomplished
that by when the "Yes" was to be hidden (determined by checking
el.getAttribute('data-value') == 'Yes'
as I noticed the data-value
attribute when looking at the HTML), instead hiding the ancestor of it
that was the element for the entire section. I determined which ancestor
simply by repeating .parentNode
and re-running the script in the
JavaScript console until it did what I expected.
Putting it all together, here's the final script:
document.querySelectorAll('.isDisabled:not(.isChecked)')
.forEach(el =>
(el.getAttribute('data-value') == 'Yes'
? el.parentNode.parentNode.parentNode
.parentNode.parentNode.parentNode
.parentNode.parentNode
: el)
.style.display = 'none');
Making the bookmarklet#
Now that we have our script, we can convert it into a bookmarklet. A URI is a single line of text, and wrapping the code in an anonymous function prevents variable name collisions. I used this encoder which does both for you. I also found another blog post of useful tips for building bookmarklets, including pointing out that if you're worried about the size of your bookmarklets, you can make your bookmarklet actually just be a small reference to an external JavaScript file that hosted on a web server somewhere.
Comments
Have something to add? Post a comment by sending an email to comments@aweirdimagination.net. You may use Markdown for formatting.
There are no comments yet.