Ajax for check?

Re: Benefits of using ajax for student quiz attempts Re: Ajax for check?

by Tim Hunt -
Number of replies: 15
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

In principle, this sounds like a good feature to go into Moodle core.

It also seems like a potentially risky feature to implement, at least initially. Therefore, if it could be done first as a plugin that brave people could try, and only later go into core, that would be the best way to handle it.

You still have not convinced me there is any need to change the core question API to do this. Once you have the $qa loaded into memory, the performance difference of rendering part vs. all of the question is minimal, as is the HTML size of the rendered question. It is just so much simpler to use the existing rendering methods, and replace the entire out question div in the attempt page HTML.

It would be really nice (e.g. for reliability) if this could be done as progressive enhancement of the existing UI (which makes this very easy to do in a plugin, since it is just extra JavaScript). Modern Moodle JS is meant to do AJAX calls using web services functions, and the Quiz web service functions that were implemented to let the mobile app work should be sufficient for this. (Or, if not, enhancing them should be the only core changes needed.)

Those are just some thoughts, though not entirely random guesses, since I made offline mode.

In reply to Tim Hunt

working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Jamie Pratt -

I've created a plugin that adds the necessary javascript to respond to the check button being pressed with an ajax call.

See :


https://github.com/jamiepratt/moodle-mod_quiz_accessrule_ajaxcheck


Unfortunately I've hit a snag, that rather embarrassingly I didn't anticipate.


When I replace the whole question html with the new question html after the responses have been processed, any javascript functionality in the question tends to break.

Although in theory javascript in question types should still work since we replace the html and the requirements_manager also outputs any required javascript calls after the replaced html, testing shows that :

  • the drag and drop words to sentence question type breaks. Any drag items that are dragged into the sentence flash into the drop zone and then move back to their original position repeatedly.
  • the essay question when using the html editor displays 2 html editors after the html is replaced.


Also the MathJAX filter on another testers web site ceases to function. I'm not sure how filters work but I suspect the required javascript calls might just happen once per page.


The plug in works wonderfully for questions that do not involve javascript. And in my testing some question types involving js seem to work well, the drag and drop marker question type seems to work OK. 


In reply to Jamie Pratt

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I have not had time to look yet Jamie, but that sounds like good work, and thank you for sharing.

There is a correct way to handle the situation where some AJAX replaces part of the page, and the JavaScript event handlers may need to re-initialise it. We needed to use it is STACK to make the Equations in the validation work with MathJax: https://github.com/maths/moodle-qtype_stack/blob/c5fa3b793cfbd997ae87c53826b9d27d43b79430/yui/src/input/js/input.js#L204

For the other issues, it probably comes down to the javascript not expecting the HTML structure to change after the page first loaded. I fear that probably needs to be investigated on a case-by-case basis, and then a fix proposed for each question type. After doing a few, it would probably be possible to write some guide lines that question type developers can follow to avoid these problems.

In reply to Tim Hunt

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Jamie Pratt -

Thanks for pointing me in the direction of that js event to notify filters of html changes Tim. The MathJax filter seems to be working for me now.

There is a handy function in the core amd module 'event' for jquery code to handle calling the event :

https://github.com/jamiepratt/moodle-mod_quiz_accessrule_ajaxcheck/commit/db1fefaae3fdbd8642ce34d3e3297f7eb996a49b



In reply to Jamie Pratt

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Jamie Pratt -

I've been experimenting some more. I was hoping to find a quick solution to get around the broken JS which I thought was caused by replacing the question html of the affected questions. I've worked on some changes to the plug in that introduce a whitelist of question types that we can safely use ajax with.

I've added a list of checkboxes to the admin menu for the plug in so that the admin can control which question types the ajax will be used with.

Then only the questions with whitelisted question types' 'Check' button has the ajax code attached. Only the questions' html which are whitelist have their html replaced.

Was hoping that I could get the ajax working with some question types and have other non whitelisted question types fall back to use the normal whole page form submission method.

Unfortunately this still doesn't fix all problems. Some question types are broken just by being on the same page as a question where we use ajax for check. The issue seems to be that the JS code attached by the requirements manager to the bottom of the question html is the code that would normally be affixed at the bottom of a page. The problems for questions that don't actually have their question html replaced include :

  • questions in the same page with html editors have an extra html editor added for each ajax call on the same page.
  • the drag and drop word to sentence plug in's drop fields get bigger each time there is an ajax call on the same page.


https://github.com/jamiepratt/moodle-mod_quiz_accessrule_ajaxcheck/tree/whitelist

In reply to Jamie Pratt

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Jamie Pratt -

Very intrepid people might want to try out the code in the whitelist branch here, either of the branches are really only for very intrepid people at this stage :


https://github.com/jamiepratt/moodle-mod_quiz_accessrule_ajaxcheck/tree/whitelist


There is a known problem that some question types' questions' JS is broken by using this ajax on the same page as them. But if you make sure you do not have the affected questions on the same page as the questions that use ajax then this plugin should work for you. You can enable the js on a per quiz basis. And you can control what question types the ajax is applied to through the admin menu.

I'm not sure I'm going to have much time to work on this or to support this plug in but I may continue to tinker with this interesting problem.

In reply to Jamie Pratt

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Jamie Pratt -

I fixed it.

The plug in now should just ignore questions of a type that have not been whitelisted in the plugins admin settings. The ajax should work for all the question types that are whitelisted by default.


For questions where the question type is not whitelisted the check button will work as normal.

Use the master branch which now has the whitelist branch merged into it if you want to try this plug in out.



Technical details follow.

------


I have fixed the issue with the js of other questions on the same page breaking.

I noticed that when using my code with the white list of question types when only the first question on the page was using ajax then the other questions on the page were not affected.

This led me to suspect that

$PAGE->requires->get_end_code()

Outputs the required end code for all rendered questions. So if we render first question for slot 1, we apparently get the required end code for slot 1. Then when we render the html for slot 2 we get the end code for slot 1 and slot 2.

I decided that rather than render all slots html I would only render the html for the slot where the submit button had been pressed.

In reply to Jamie Pratt

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Andrew Barrett -

Thank you again for this Jamie, I really think this is a useful addition to "modernising" moodle.

One small issue thing I picked up when using the Ajax call is if I want to leave the page without going through Finish attempt and Submit all and finish, I get a browser warning me about losing info if I leave the page (both chrome and edge). This is even if I have already completed the question or want to leave after receiving a hint but not selecting Try Again.


In reply to Andrew Barrett

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Jamie Pratt -

Ah!

That must be the autosave js. It is detecting the changes made by our js to the sequence check hidden field in the quiz form I think.

If Tim sees this post then he might be able to suggest how we can tell the autosave js to ignore these changes. If not I'll have a look through the autosave js in the next few days.

In reply to Andrew Barrett

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

This is probably coming from formchangechecker. I think that, once you have successfully processed an Ajax submission, then you need to call

M.core_formchangechecker.reset_form_dirty_state();
(Do you have to worrk about if the student has started answering a different question before the first question Ajax sumbit completes?)

Average of ratings: Useful (1)
In reply to Tim Hunt

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Jamie Pratt -

Thanks Tim.

It seems that the formchangechecker ignore any elements with the ignoredirty class so I set this class on the sequencecheck hidden fields and also the "Check" submit button which was also triggering the change checker when changing the label on the button to "Checking...."


In reply to Jamie Pratt

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Daniel Thies -
Picture of Core developers Picture of Plugin developers Picture of Testers

Hello Jamie,

This look like a very worthwhile improvement. I noticed a couple of odd items during testing. Checking questions in reverse order causes a popup submissionoutofsequencefriendlymessage warning.

Enabling glossary autolinking filter causes a javascript error in the console when the question is reattempted.  The glossary filter uses AJAX for the popup and sends an filter content update system. However, it does not seem to affect functionality.

Average of ratings: Useful (1)
In reply to Daniel Thies

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Jamie Pratt -

Thanks for the bug report Daniel!

I've found the problem that was causing "submissionoutofsequencefriendlymessage"s to appear. The newest code is up on github.

In reply to Tim Hunt

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Brendan Heywood -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
hi Tim,


We are working on an alternate 'simplequiz' activity which has essentially zero "chrome" and does everything via ajax with a 'check' button broadly very similar to Jamie has done. We need to go through and add support for each question type that uses JS in order to get it working, and ideally we'd like to get this upstreamed - so I'm after your feedback.

Our first thought was that each question would also implement a notifyFilterContentUpdated listener and then fire it after our ajax load, and then it would broadly do whatever it needs to re-init, in most cases very similar to it's original init code. But I don't think this would go upstream as it's dead code in the question type which is only getting fired by our simple quiz activity.

So now I'm thinking a better approach is that instead of a question type, eg ddimageortext, declaring to page via $PAGE->requires->yui_module or via AMD there there is some initialization code to run, instead it can choose to *only* listen to notifyFilterContentUpdated, and the question bank render code fires this event on page load. If will init, or re-init, as needed.

This way existing questions which have normal init code will continue to work (they will ignore the event and won't work via ajax but still work on pageview), and any questions we touch which choose to implement notifyFilterContentUpdated will work in both situations but without introducing any dead code.

Would you broadly support that approach?

I can't see any trackers yet around this, so I'll make that as needed.

In reply to Brendan Heywood

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I think you should avoid anything that requires changes on a per-question-type basis if at all possible.

Or, at least, not require anything new to be done on a per question-type basis. There is already code in some question types to support the Mobile app. Is any of that reusable? (I must admit woeful ingnorance of how Quiz in Mobile app works. I really ought to make the time to learn.)

It is possible to write JavaScript using approaches like delegated event handlers, which when done well means that the same JavaScript will work even if the HTML content changes. (It is also good practice for other reasons.) If we have to make changes to the JavaScript of individual question types, would it be possible to actually make changes like that - which are generally good, not specifically for your application. Doing that would be uncontroversial, I think. (A lot of qtypes have old JavaScript that certainly does not follow best practices. Or, at least, today's best practices.)

Have you made a list of all the question types (that you are interested in), and how badly broken they are without changes? It would be interesting to see that.

In reply to Tim Hunt

Re: working on plug in to introduce ajax functionality for quiz attempt (was Re: Ajax for check?)

by Brendan Heywood -
Picture of Core developers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

thanks heaps Tim,

Yes we are very keen to try and find an agnostic solution so we don't have to touch each question, but so far I can't see how that's possible. Some are yui, some are amd, they can bootstrap differently, and who knows about the plugins in the wild not in core. We haven't done an exhaustive audit of what questions we want (in core + plugins) vs which are broken, but drag and drop is definitely in the list, and is broken.

Anyway we are going still scoping the second stage and getting funding, we should know more in a month or so. At this point it looks like we will aim for the notifyFilterContentUpdated solution - which as you've said should hopefully be uncontroversial.

thanks again