Field for typedAnswer on answer card

It feels a bit stupid to be asking this question – I hope there’s a simple answer I’m just not seeing. But I’ve been trying to figure out how to display only the typed answer from the question card, on the answer card. I’d like to do this so I can compare the typed answer to a list of possible correct answers on the answer card (e.g., alternate meanings of a foreign word).

Right now, it seems as though the type: filter shows a difficult-to-parse diff of what you type vs. what the card thinks the answer is. What’s more, due to how the field is filtered on the answer page, it’s very difficult to strip out all of the HTML cruft as well as the added dashes for what it thinks you “missed.”

I tried creating a hooks.field_filter for this, but wasn’t successful. I was trying to get at the mw.reviewer.typedAnswer field, but it seems as though that variable isn’t set yet when the field filters are run. As it stands, I’m using a gui_hooks.card_will_show hook to add the value on answer cards. Something like this:

def card_will_show(html: str, card: Card, ctx: str):
    if not ctx.endswith("Answer"):
        return html

    return html + f'<span id="typed-answer" style="display: none">{mw.reviewer.typedAnswer}</span>'


gui_hooks.card_will_show.append(card_will_show)

But that’s a bit inflexible, because ideally I’d like my card template to control how the answer shows up, and this only gives me a piece of the puzzle. I’ll add JavaScript to compare the contents of the <span> to the list of available answers, but it’d be equally nice to be able to simply drop in a field or filter into my answer card template like this (after creating an appropriate hooks.field_filter):

Your answer:
<p class="typed-answer">{{typedAnswer:}}</p>

Any thoughts?

If you just want to get the text, which is typed into an input box, on the back side, you can do it with javascript without add-ons. Here is a card template example:

Front template
{{Front}}
<div>
    <input id="input-box" type="text" autofocus placeholder="Type your answer here...">
</div>
<script>
    var isAnkiPc21 = typeof pycmd !== 'undefined';
    var typedAnswer = '';
    var inputBox = document.getElementById('input-box');
    inputBox.addEventListener('input', (event) => {
        typedAnswer = event.currentTarget.value;
        if (!isAnkiPc21) {
            // AnkiDroid, AnkiMobile, AnkiWeb
            try {
                sessionStorage.setItem('typedAnswer', JSON.stringify(typedAnswer));
            } catch (error) {
                console.log(`${error.name}: ${error.message}`);
            }
        }
    });
    if (isAnkiPc21) {
        setTimeout(() => inputBox.focus(), 0);
        // aqt_data/web/js/reviewer.js > function _typeAnsPress()
        inputBox.addEventListener('keypress', _typeAnsPress)
    }
</script>
Back template
{{Front}}
<hr id=answer>
{{Back}}
<div id="typed-answer"></div>
<script>
    var output = '';
    if (typeof typedAnswer !== 'undefined') {
        // Anki 2.1(PC)
        output = typedAnswer;
    } else {
        // AnkiDroid, AnkiMobile, AnkiWeb
        try {
            output = JSON.parse(sessionStorage.getItem('typedAnswer'));
            sessionStorage.removeItem('typedAnswer');
        } catch (error) {
            output = `${error.name}: ${error.message}`;
        }
    }
    document.getElementById('typed-answer').textContent = `Your answer: ${output}`;
</script>

I have tested the card template on Anki PC(2.1.38), AnkiDroid, and AnkiWeb. FYI, it might be better to use anki-persistence for data persistence between front and back.

4 Likes

Thanks for the response! I hadn’t even considered session storage, but it makes sense.