It is not obvious how to inject a service into a controller in Drupal 8. You actually need to use a create() function to do that.
Drupal 8 Form API supports form states, that allow to ad jQuery behaviors with form API. To do that, however, you need to convert the element's parents array into the notation like field_body[subform]. This utility function concatenates the element's parents array into the required notation.
Drupal 8 has a powerful mechanism to temporarily store data. Tempstore resembles storing data in session, and it also persists between the page reloads. There are two major types of storage that I ended up using: private tempstore and shared tempstore.