How do I synchronously sync changes in AnkiWebView to the data model in Python?

I’m writing an add-on that formats selected text in Anki’s editor. The way it works is roughly as follows:

editor.web.eval(f'''
  // some JS code that uses Ranges API to wrap
  // a selection with <span id="{random_id}">
''')
transformed_field = transform_the_selected_span(random_id, editor.note, editor.currentField)
editor.note[editor.currentField] =  transformed_field

Now this doesn’t work, because eval executes asynchronously. My problem is that evalWithCallback also doesn’t work for this use-case, because editor.note is not updated when the callback executes.

I currently mitigate this problem by having a dialog shown after eval, which causes the update to happen, like this:

editor.web.eval(f'''
  // some JS code that uses Ranges API to wrap
  // a selection with <span id="{random_id}">
''')
params = QInputDialog.getText(foo) # get some parameters from the user
transformed_field = transform_the_selected_span(random_id, params, editor.note, editor.currentField)
editor.note[editor.currentField] =  transformed_field

How could I avoid needing this trick? Is there a way to either have the editor’s webview flush changes to editor.note?

After making changes to editor.note, you’ll probably need a call to loadNoteKeepingFocus()

2 Likes

Thank you, it works. I’ve applied your advice to implement a continuation callback like this:

def cont(field):
  transformed_field = transform_the_selected_span(random_id, field)
  editor.note[editor.currentField] =  transformed_field
  editor.loadNoteKeepingFocus()

editor.web.evalWithCallback(f'''
  // some JS code that uses Ranges API to wrap
  // a selection with <span id="{random_id}">
  // return the entire field
''', cont)
1 Like