How does saving progress work?

otacke's picture
Forums: 

I glanced at some of the content types in order to identify the way that the progress or state is saved, but so far I have only found the code for retrieving those two from contentData. How does storing work? 

tomaj's picture

Hi Oliver,

The content type needs to implement the getCurrentState method, which enables saving objects, that are returned later as contentData.

The getCurrentState function is called in regular intervalls, as well as being triggered on most xapi statements.

- Tom

otacke's picture

Thanks, Tom!

otacke's picture

I had a look at it. Very simple if you stay within your own content type. Nice! But it seems to be a little more tricky if you build upon other libraries (which in turn may build upon other libraries) as "Document Tool" does. Is there any recommended approach to tackle this problem? Would implementing a serialize/deserialize methods for each library that could be called by other libraries be a clean solution?

tomaj's picture

I don't think there are that many cases where the libraries has a state, so I've not encountered this problem myself.

But yea, I think letting a library keep the code for serializing/deserializing (maybe trough a getCurrentState-method) would be the easiest way.

- Tom

otacke's picture

I encountered that problem yesterday when having a brief look at the documentation tool, but maybe I simply don't see the obvious. It references several "page" libraries that in turn use a variable number of TextInputFields, etc. If I wanted to store the content state of the documentation tool, I'd have to collect all the current values of fields and parsing the DOM seemed to be a little weird to me.

tomaj's picture

I think it depends a bit on what you are trying to do.

For most content types some user input is stored as a member variable when submitted, so it's easy to access from getCurrentState. But in other cases (like Documentation tool), it needs to grab fresh data the dom.

Do you have some code to share, maybe I can provide some better feedback?

- Tom

otacke's picture

I was actually looking at Documentation Tool for a colleague who would love it to save the content state. I figured that I couldn't do it in a couple of hours, but maybe I missed something.

tomaj's picture

Ah ok.

I've not worked on Documentation Tool myself, so I don't know alot about it. But good luck, if you're going to try to sort it out! :)

- Tom

otacke's picture

I guess I will, but my list of stuff I could do for H5P is growing longer every day and there's this nasty thing called job that takes quite some time ;-)

tomaj's picture

Hehe

otacke's picture

What about this code? It could be used to build something like a "getCurrentState cascade" from "Document Tool" over "standard page" (and the other three page libraries) down to "text input field" (and the other basic libraries).

I tested it with my demo of Essay that also uses "text input field" and now can store the user's text. Works fine.

tomaj's picture

I just glanced over the pull request, and it looks pretty straight forward.

We are just finishing up a release here now, so I created a task for reviewing your pull request, and assigned it to the next upcoming release (Thrud).

- Tom

otacke's picture

Thanks! Enjoy you day of awesomeness when the release is done :-) You will have earned it.

tomaj's picture

Thanks! Sure I'll enjoy my "day of coolness", and I'll work on my new combine the pairs content type.

- Tom

otacke's picture

Gee, nice. It's often used when teaching languages AFAIK. It will probably be pretty useful to a lot of people.

serettig's picture

Hi tomaj,

is having a getCurrentState() method all that is necessary to store the state or do I also have to implement xAPI? So far, I've put in getCurrentState() but not implemented xAPI besides calling triggerXAPI('interacted') when the user does something of relevance. However, getCurrentState() is never called. In h5p-blanks it seems that it is called when creating the xAPI template for the event 'answered'. So must it be called manuelle after all or can getCurrentState() be considered a virtual method that I can override and is called by parent code?

Thanks
Sebastian

otacke's picture

If implemented in your content type, getCurrentState() is called by the h5p-php-library automatically in regular intervals, given that you activated the Save Content State option in your plugin's settings. You don't need xAPI statements here, although those containing the verb completed or progressed also trigger saving the current content state if the Save content State option is set.

serettig's picture

Thanks, I didn't have Save content State enabled in Drupal. Now it works!

otacke's picture

Just a question that crossed my mind: In order to store a user's input within the host system, he/she needs to be logged in. This makes sense in course-like settings, but there may be scenarios where users are not required to log in somewhere but you still want to give them the opportunity to interrupt their work and continue later on. In that case would it be feasible to store the data in a cookie and to retrieve it from there? Storing the data within the host system should still be prioritized because this way users are more flexible with using different devices. However, having a cookie as a fallback solution might be nice. What do you think?

thomasmars's picture

Yes, this might be useful. Perhaps it should be stored using the web storage API though, since it does not really need to be sent to the server.

otacke's picture

I'll put it on my list ... :-D

otacke's picture

Hi Thomas!

This is a thread well aged now :-D Do you think there's any reason (security in particular) for not pursuing this?

  1. Use regular save content state for users who are logged in.
  2. Use local storage for users who are not logged in.
  3. Use local storage for users who are logged in instead of the regular save content state (would mean less traffic/storage required which could make sense for web servers with tiny resources).
  4. Use local storage for users who are logged in as a backup in addition to regular save content state. Could be useful to prevent the need to start over if the author just corrected a typo (did that for H5P.Cornell where it makes sense not to touch the students' notes). Downside: The host system should provide a mechanism to force a task reset if the author really requests it.

Keeping it at 1 and 2, maybe also 3 could be a reasonalbe step already. I just wonder if the local storage should be an extra option in the host system settings or if it should be automatically included in the save content state option (thus ruling out 3). And which storage (database vs. local storage) should take precedence if someone has two states, one from not being logged in (local storage) and one from being logged in (database)? Could be solved by comparing timestamps, just needs to be done ...

Cheers,
Ollie

 

thomasmars's picture

Yes, I see no problems having local storage in addition to save content state.

otacke's picture

Cool! I guess I might implement that very soon then.