Some questions/thoughts concerning the answer field

Dear all,

I hope this is the right category for my problem …

So far, I have not found a proper solution for this problem described here … despite some
longer Google research.

So I hope that someone can help me … and please be patient, maybe my explanations have
become a little bit detailled …

I have some programming experience, but not concerning web programming, and at the moment, I’d like to put my focus on learning Latin.

Learning a new language always means: practising, practising …

In order to do this, I adapted this Anki Grammar Template

… adapted means: I changed the colors, the fonts, and removed the appendices, but I
haven’t understood all the details of the javascript code … it’s beyond my knowledge :slight_smile:

Anyway … the code was working with may adaptions, but while preparing my grammar cards,
a problem occured … I have to illustrate it a little.

Consider the Latin noun origo ( = “origin” in english) … the dictionary says

orīgo, orīginis, f

which means: a feminine noun, third declension with consonant stem.

Now I wanted to create a grammar exercise “Fill in the noun with correct declension” when
an adjective is given:

(origo) _____ alienae

In Anki, it would look like

{{c1::####SOLUTION HERE####::(origo)}} alienae

If we take a closer look at the adjectice alienus, -a, -um … it’s 1. & 2. declension …
and now, three answer are possible:

originis alienae => genitive singular
origini alienae => dative singular
origines alienae => nominative plural

To solve this, here’s what I thought of:

We define a separator, e. g. “&&”

{{c1::originis&&origini&&origines::(origo)}} alienae

And indeed … executing this piece of javascript on the backside shows me
the solution string with the answers concatenated by “&&”:

var elements = document.querySelectorAll(".cloze");
var length = document.querySelectorAll(".cloze").length;

for ( i = 0; i < length; i++ )
   alert (elements[i].textContent);

So I thought of implementing my own javascript comparison … although I mentioned
above that my focus is Latin, but for this routine, I only need some basic javascript
knowledge …

But … executing this

alert (document.getElementById("typeans").innerHTML ) ;

leads to:


This is the result of the comparison … how can I access the answer I typed in at the front side?

Obviously, I need these answer to implement my own comparison - any ideas/proposals?

I thought of setting a hint field on the back side, which says: “Others solutions are possible” or
so … would be a nice feature … if I only knew about the contents of the typed answer on the
back side …

Another option is: my thought are completely wrong … if this is true, feel free to tell me :slight_smile:

By the way: Anki is a great tool for language learning, so I’d like to learn something more about
the details … not at the moment, of course, but in the future. As far as I know, Anki uses HTML
templates … I don’t know much about this … which template engine uses Anki, and do you know
a good point to start?

And I recognised that testing the routines with javascript-alert’s is a little bit cumbersome … do
you know a simpler way? Is there a possibility to integrate this in the Eclipse IDE, for example?
With such an IDE, it is a little bit simpler to debug javascript, for example …

Thanks for your efforts, and for reading my mail … Kind regards, Frank

AFAIK Anki doesn’t use an engine for the templating, but has its own implementation.

Cards are displayed in a webview, which means they’re like little websites.
If you learn a bit of web development (HTML/JS/CSS), you can make your cards do anything. Anything that works in a web browser will work on Anki cards too.

My go-to method is to use console.log(...) and then inspect the previewer with the add-on AnkiWebView Inspector.

You could also use remote debugging as described here: How to see card preview's browser console - #3 by gla23

Using an IDE is a bit too much effort to set up in most cases. There’s no native integration for IDEs. But you could create a sample HTML file to test your scripts on / inspect it in the browser.


Thanks a lot for answering my question!

Your proposals were very helpful.

Yes, console.log(...) is a lot more comfortable than javascript-alert's … and AnkiWebView works
really good.

In the meantime, I’ve found an idea for my answer field problem here at Reddit.

The solution presented there was not working out of the box, but with some adaptions, I think I got a
suitable solution … for now, because I think applying a set of regular expressions to all these “-” which
appear in the comparison might not be the best solution, because a “-” can be part of the answer … if
we find one exception, we have to modify the RegExp’s and make sure sure this is going to work with
all the rest …

I define a hidden field into which the “reconstructed” answer is written:

<div style="display:none;">
<span id="typedanswer"></span>

console.log ( "Daten: "+document.getElementById("typeans").innerHTML );
var inp = document.getElementById("typeans").innerHTML.split('↓')[0];
console.log ( "[0] : " + inp );
var replaceT = [
 /\<code id\="typeans"\>/g,
  /\<span class\="typeBad"\>\-+\<\/span\>/g,
  /\<span class\="typeGood"\>/g,
	/\<span class\="typeBad"\>/g,
for(var x = 0; x < replaceT.length; x++){ 
  inp= inp.replace(replaceT[x],""); 
	console.log ( "x= "+x+"   "+replaceT[x] + "   "+inp);
console.log ( inp );

document.getElementById("typedanswer").innerHTML = inp;
concole.log("TypedAnswer = "+document.getElementById("typedanswer").innerHTML);
var elements = document.querySelectorAll(".cloze");


This is going to take some time to test in the routines, if this really works correctly …

In the meantime, the problem with “origo” described above can only have one possible solution :slight_smile:

Anyway: we don’t have to consider all eventualities and special cases if we begin to learn a new
language … at the moment, it is more important to get an insight into all these declinations and
conjugation to go “per aspera ad astra” :slight_smile:

But if you have a better idea for solving this or find out that something is wrong with those
regular expressions and has to be corrected, please let me know.

Kind regards, Frank

Dear all,

I made some tests with the regular expressions above in the meantime - apparently, they do their work
with some modifications.

But that solution was not satisfying.

I found another approach here at Reddit., which has been mentioned here in the forum too.

I “played” a little bit with the anki-persistence-solution - and was able to test it with my desktop
(Suse Linux 15.2, Anki 2.1.44) and my Android tablet (Android 12) - here’s the code:

Front template
var timestamp = new Date();
// v0.5.2 -
if (void 0 === window.Persistence) {
    var _persistenceKey = "",
        _defaultKey = "_default";
    if (window.Persistence_sessionStorage = function() {
            var e = !1;
            try {
                "object" == typeof window.sessionStorage && (e = !0, this.clear = function() {
                    for (var e = 0; e < sessionStorage.length; e++) {
                        var t = sessionStorage.key(e);
                        0 == t.indexOf(_persistenceKey) && (sessionStorage.removeItem(t), e--)
                }, this.setItem = function(e, t) {
                    void 0 == t && (t = e, e = _defaultKey), sessionStorage.setItem(_persistenceKey + e, JSON.stringify(t))
                }, this.getItem = function(e) {
                    return void 0 == e && (e = _defaultKey), JSON.parse(sessionStorage.getItem(_persistenceKey + e))
                }, this.removeItem = function(e) {
                    void 0 == e && (e = _defaultKey), sessionStorage.removeItem(_persistenceKey + e)
            } catch (e) {}
            this.isAvailable = function() {
                return e
        }, window.Persistence_windowKey = function(e) {
            var t = window[e],
                i = !1;
            "object" == typeof t && (i = !0, this.clear = function() {
                t[_persistenceKey] = {}
            }, this.setItem = function(e, i) {
                void 0 == i && (i = e, e = _defaultKey), t[_persistenceKey][e] = i
            }, this.getItem = function(e) {
                return void 0 == e && (e = _defaultKey), t[_persistenceKey][e] || null
            }, this.removeItem = function(e) {
                void 0 == e && (e = _defaultKey), delete t[_persistenceKey][e]
            }, void 0 == t[_persistenceKey] && this.clear()), this.isAvailable = function() {
                return i
        }, window.Persistence = new Persistence_sessionStorage, Persistence.isAvailable() || (window.Persistence = new Persistence_windowKey("py")), !Persistence.isAvailable()) {
        var titleStartIndex = window.location.toString().indexOf("title"),
            titleContentIndex = window.location.toString().indexOf("main", titleStartIndex);
        titleStartIndex > 0 && titleContentIndex > 0 && titleContentIndex - titleStartIndex < 10 && (window.Persistence = new Persistence_windowKey("qt"))
timestamp = new Date() - timestamp;
$(document).ready(function() {
    // document is loaded and DOM is ready
//     alert("document is ready");

$(window).load(function() {
    // page is fully loaded, including all frames, objects and images
    alert("window is loaded");

$(document).unload(function() {
    // do validation here

alert ( "d unl" );

<div id="front"></div>

var number = 0.2564;
var text = "Initial";
// Check whether Persistence works on the client.
if (Persistence.isAvailable()) {  
	// Retrieve a previously stored number and override the default. 
	// (In case this is executed on the backside as well by {{FrontSide}})
 	number = Persistence.getItem(); 
	if (number == null) {
		text = "A text";
		Persistence.setItem("nu",  "1. xyz " +number);
		Persistence.setItem("nu2", "1. *** " +number);
//		Persistence.setItem("tu1", "1. *** " +text);

window.front.appendChild(document.createTextNode(number)); // Print the number.

window.onsubmit = function(event)
	alert("Onsubmit: "+Persistence.isAvailable());
	var number = 0.2564;
	var text = "Initial";
	if (Persistence.isAvailable()) {

		text = "A text";
		Persistence.setItem("nu",  "2. xyz " +number);
		Persistence.setItem("nu2", "2. *** " +number);
		Persistence.setItem("tu1", "2. *** " +text);

Back template
// v0.5.2 -
if(void 0===window.Persistence){var _persistenceKey="",_defaultKey="_default";if(window.Persistence_sessionStorage=function(){var e=!1;try{"object"==typeof window.sessionStorage&&(e=!0,this.clear=function(){for(var e=0;e<sessionStorage.length;e++){var t=sessionStorage.key(e);0==t.indexOf(_persistenceKey)&&(sessionStorage.removeItem(t),e--)}},this.setItem=function(e,t){void 0==t&&(t=e,e=_defaultKey),sessionStorage.setItem(_persistenceKey+e,JSON.stringify(t))},this.getItem=function(e){return void 0==e&&(e=_defaultKey),JSON.parse(sessionStorage.getItem(_persistenceKey+e))},this.removeItem=function(e){void 0==e&&(e=_defaultKey),sessionStorage.removeItem(_persistenceKey+e)})}catch(e){}this.isAvailable=function(){return e}},window.Persistence_windowKey=function(e){var t=window[e],i=!1;"object"==typeof t&&(i=!0,this.clear=function(){t[_persistenceKey]={}},this.setItem=function(e,i){void 0==i&&(i=e,e=_defaultKey),t[_persistenceKey][e]=i},this.getItem=function(e){return void 0==e&&(e=_defaultKey),t[_persistenceKey][e]||null},this.removeItem=function(e){void 0==e&&(e=_defaultKey),delete t[_persistenceKey][e]},void 0==t[_persistenceKey]&&this.clear()),this.isAvailable=function(){return i}},window.Persistence=new Persistence_sessionStorage,Persistence.isAvailable()||(window.Persistence=new Persistence_windowKey("py")),!Persistence.isAvailable()){var titleStartIndex=window.location.toString().indexOf("title"),titleContentIndex=window.location.toString().indexOf("main",titleStartIndex);titleStartIndex>0&&titleContentIndex>0&&titleContentIndex-titleStartIndex<10&&(window.Persistence=new Persistence_windowKey("qt"))}}


<div id="back"></dv>

var number= 0.4;
var number2=0.8;
var t1 = "";
try {
	if (Persistence.isAvailable()) {

  	number = Persistence.getItem("nu" );
  	number2 = Persistence.getItem("nu2" );
	  t1 = Persistence.getItem("tu1");
	window.back.appendChild(document.createTextNode("*** " +number+" "+number2+t1));
catch(e) {
	window.back.appendChild(document.createTextNode("Error: " + + " - " + e.message));

As described in the post mentioned above, it should be possible to introduce a text input field
and store the input text by something like that:

    var inputBox = document.getElementById('input-box');
    inputBox.addEventListener('input', (event) => {
        typedAnswer = event.currentTarget.value;

I added an input field, it works in my desktop - but how do you enable the soft keyboard under Android to input text? The input box appears - but no keyboard :slightly_smiling_face: I have tried some solutions by searching on Google - without success so far …

Have you got any ideas how to activate the Android keyboard?

What happens if we press the “Show Answer”-button? It is not a submit, isn’t it? As far as I know,
only HTML forms can be submitted, and there is no HTML form in this case? This means
implementing a “window.onsubmit()”-routine (as I did in my front template) is usless?

Furthermore, I hope someone can give me another advice.

I have programming skills - and worked on web projects in the past, but that was 20 years ago.
My knowledge needs some updates.

I found two courses on Udemy which have very good reputations:

As far as I was able to see, the course from Colt Steele is a little bit more detailled, and he covers
HTML templates, too.

I guess I need the sections about CSS, the details of HTML and some details on Javascript …
What do you think, what will I need additionally? JQuery?

What’s your opinion? Would you recommend the course of Colt Steele?

Since my last post, I was able to make progresses in learning Latin - thanks to the abilities of Anki.

I enjoyed the styling of card templates …

What I would like to achieve: a template where I can input all the forms of a Latin noun, a whole
declination, so to say … and I think this can be reached with these persistence solution.

Each form has its own input box, will be stored in the session storage, and can be read and
checked on the back template.

Thanks a lot in advance for your efforts.

Kind regards, Frank

Dear all,

if it is interesting for you: I made some more investigations in the past few days.

  • This commentary on Github solved my keyboard problem on Ankidroid.
  • I think this add-on will be useful to solve my question concerning the submit-question described above.
  • The courses I mentioned are also available on Youtube - I chose the one of Colt Steele.

My first goal was to build the basic knowledge in Latin … together with the course and the solutions I found I should be able to solve what I mentioned in my last post (exercising a whole declination) … it’s the best way to update one’s knowledge.

In my post in January, I mentioned that I have no experiences “concerning web programming” - this formulation was a little bit unfortunate or awkward … since I worked on web projects in 1999/2000, it is a little bit like having no experiences now … it was not my intention to be dishonest, so I’d like to apologize for my mistake.

Kind regards, and thanks again for your patience, Frank