How to create a script that modifies the content of the fields?

Hello. I need to create a script that takes a word from the first field of the card, modifies the sentence from the second field, and displays the modified result.
The script on the front side should replace the word with underscores. On the back, it should wrap the word in <b></b> tags to make it bold. Example:

Word: weather
Sentence: The weather yesterday was good.

Front side output: The ___ yesterday was good.
Back side output: The weather yesterday was good. (The <b>weather</b> yesterday was good)

I wrote some code that works well in browsers, but it doesn’t work in the Anki app. Could somebody, please, help me to understand why it doesn’t work?

Front side:

<div>Front</div><hr><br>

<div class="word" style="display:none">{{Word}}</div>
<div class="sentence" style="display:none">{{Sentence}}</div>

<div class="output1"></div>

<script>

      let word = document.querySelector(".word").textContent;
      let sentence = document.querySelector(".sentence").textContent;

      document.querySelector(".output1").textContent = sentence.replace(word, "___");

</script>

Back side:

<div>Back</div><hr><br>

<div class="word" style="display:none">{{Word}}</div>
<div class="sentence" style="display:none">{{Sentence}}</div>

<div class="output2"></div>

<script>

      let word = document.querySelector(".word").textContent;
      let sentence = document.querySelector(".sentence").textContent;

      document.querySelector(".output2").innerHTML = sentence.replace(word, "<b>" + word + "</b>");

</script>

By deleting “let” your script seems to work fine for me:

Front script:

<script>

      word = document.querySelector(".word").textContent;
      sentence = document.querySelector(".sentence").textContent;

      document.querySelector(".output1").textContent = sentence.replace(word, "___");

</script>

Back script:

<script>

      word = document.querySelector(".word").textContent;
      sentence = document.querySelector(".sentence").textContent;

      document.querySelector(".output2").innerHTML = sentence.replace(word, "<b>" + word + "</b>");

</script>
2 Likes

It works indeed! Thanks!
But how the hell do these variables work without declarative words (let, const, var)?

A new problem has arisen. Replacing replace() method with replaceAll() makes the code broken. Is there any way to make the replaceAll() method work properly?

(Disclaimer: I am not a programmer, so my knowledge on the subject is limited and what I say might not be correct)

About the first question: as far as I know, it is not strictly necessary to use declarative words, but you are always advised to, as sometimes problems might happen if you do not. Neither let or const seem to work with your script, while var seems to work fine.
From https://www.w3schools.com/js/js_variables.asp :

Always declare JavaScript variables with var , let , or const .
The var keyword is used in all JavaScript code from 1995 to 2015.
The let and const keywords were added to JavaScript in 2015.
If you want your code to run in older browser, you must use var

That said, I personally have some scripts in which const is used and they all function fine. So I do not know what might be the issue in this case.

About the replace() vs replaceAll() part: I don’t think replaceAll() is needed to accomplish what you’re trying to, you can use RegEx with the g (global) modifier. See my reply in your other topic

1 Like

Now you might ask: “What is the issue with using block scoped variables at the top level of a <script> tag, i.e. why is const and let working inside functions, but not outside?”

A variable with the same name must not be declared multiple times in the same scope using the let or const keywords.

Consider this script:

let num = 1
let num = 42

The second line will throw the following error:

Uncaught SyntaxError: Identifier 'num' has already been declared.

Say you used let/const at the top-level of a <script> tag, which is the outermost scope. When Anki executes that script twice in the same context (i.e. when switching to a new card), it will throw that error.

This wasn’t an issue before Anki switched to persisting its webview during review. Before 2.1.41, the whole document was refreshed with each card, so you could use let/const/var interchangeably.

Now, you’ll need to use var at the outermost scope.

3 Likes

(for the record, older Anki versions used a persistent webview too; I believe the change in behaviour was when we moved away from using jquery to update the HTML)

1 Like

So var works for variables but what about class definitions? I tried creating a class but it won’t work on back side because it says it is already declared? Can one assign a class to a var?

Yes, with class expressions: Classes - JavaScript | MDN

I think if you wrap your whole front scropt in an IIFE, a class should also be contained, regardless how you declare it.

2 Likes

If you want to know the proper difference between let and var, I would recommend reading the Mozilla documentation on that topic.

3 Likes

Awesome thanks guys! JS is kind of a weird language in that it seems easy but it is not with a lot of really weird but hugely important distinctions/idiosyncrasies.

Yes, and you haven’t reached yet (I think) the point where you try to understand its terrible type system (which, in retrospect, is probably one of the worst ever created). This stems from the historical development of JS: in the old days, when they started working on a new feature, they used to put it in an “experimental” standpoint, where it was usable but it could be (theorically) removed or modified in a breaking way at any time. This did not prevent these features to spread very widely, and, when the JS team wanted to modify or delete that feature because it did not interact well with the rest of the language, they simply couldn’t, because it was already used everywhere. This, in combination with the fact that JS interpreters (as HTML parsers) where in some kind of “competition” (because, if one browser is more restrictive on which JS features it “accepts”, trying to follow the recommendations of the JS dev team, it essentially means for the end user that this browser is just less good, because less sites will work with it; after all, if a developer makes a single syntax error in a function barely used, a good web browser is still able to provide a smooth experience while that function is not used, rather than simply refusing to load the page) lead to this strange situation where we are now.

However, this is not what actually lead to several variables declaration variants. This is more related to the fact that there was, on the one hand, a huge pressure to make JS fast (Google alone invested astronomical amounts of money in squeezing the performance out of the language; which is why their JS engine is the most widely used), and, on the other hand, a language whose original design wasn’t at all though to be efficient (to be understood: efficiency was not the main goal the JS creators had in mind). For this reason, some syntax quirks were later added to “patch” the original design in order to provide easy and yet very big performance improvement, including several ways to define / declare variables.

And this “stretch” from the original design and plan of JS, and what it is used for today, is a big reason for these idiosyncrasies, as you put it. To give an example: since JS was intended to be used on a web browser, where resources (including images) would be loaded through a slow internet connection, it has first class support for asynchronous programming, making it almost seamless to do what may be very painful in other languages. This makes sense if JS is executed in a web browser. But if you start using it as a general purpose language, with projects like nodejs, then these choices become very weird. Why specifically a good support for asynchronous programming, but a terrible handling of stdin / stdout (which, in a web browser, is of course useless).

2 Likes

Interesting. Thanks for the thorough explanation! That definitely makes sense how it would end up like this. Maintaining backwards compatibility would have been key to keeping users and thus just staying relevant even if it means new users would have a few initial headaches.

BTW, I am really very thoroughly impressed with how much effort and time you all take to explain things to everyone who asks questions! I’d say the best part of Anki is just the community support! These explanations have very thorough and in-depth. Thanks for all the info! <3

3 Likes