Recommended method to attach an EventListener to a H5P field?
My approach to attach an EventListener to a H5P field:
Let semantic.json define a field e.g. named "dataexchangeMode".
... { "name": "dataexchangeMode", "type": "select", "label": "Automatic/Manual Mode", "description": "Lets you choose if auto or manu", "options": [{ "value": "auto", "label": "auto selected" }, { "value": "manu", "label": "manu selected" } ], "default": "auto" }, ...
And let library.json define an editorDependency
... "preloadedJs": [{ "path": "scripts/dataexchange.js" }], "editorDependencies": [{ "machineName": "H5PEditor.dataexchangeEditor", "majorVersion": 0, "minorVersion": 0 } ] ...
And let library.json of H5PEditor.dataexchangeEditor load a JavaScript file:
... "preloadedJs": [ { "path": "scripts/dataexchangeEditor.js" } ] ...
Finally let this helper function be defined in dataexchangeEditor.js:
... function getFieldID(fieldName) { var result = ''; H5P.jQuery('select').each(function () { var haystack = (this.id).toLowerCase(); var needle = fieldName.toLowerCase(); if (haystack.startsWith(needle)) { result = this.id; } }); if (result == '') { H5P.jQuery('input').each(function () { var haystack = (this.id).toLowerCase(); var needle = fieldName.toLowerCase(); if (haystack.startsWith(needle)) { result = this.id; } }); } return result; } ...
Then we are able to find the DOM element (when DOM is loaded) by retrieving its HTML id, using the helper function, and we can attach an EventListener for the 'change' event to this element:
... H5P.jQuery(function () { var element = document.getElementById(getFieldID('field-dataexchangemode')); element.addEventListener('change', function (ev) { console.log(ev); }); }); ...
It is not possible to use this method in dataexchange.js, because the function getFieldID does not find the field-dataexchangemode-?? element.
Maybe this is, because the editor lives in an iFrame. (?)
My approach seems to be a kind of workaround. It required a bit of reverse engineering.
Is there a recommended method to attach an EventListener?
gro58
Fri, 02/04/2022 - 23:02
Permalink
Is there a recommended method
Is there a recommended method to attach an EventListener?
otacke
Sat, 02/05/2022 - 00:07
Permalink
Hi gro58!The recommended
Hi gro58!
The recommended method would be to not try to get hold of fields via the DOM but to create an editor widget such as H5PEditor.ShowWhen, H5PEditor.ColorSelector, etc.
Best,
Oliver
gro58
Wed, 02/09/2022 - 18:10
Permalink
Recommended method to attach an EventListener
Hi Oliver,
I had a look at H5PEditor.ShowWhen. I deleted the code that was responsible for show/hide, and renamed it to H5PEditor.FieldChanged.
H5PEditor.FieldChanged = (function ($) { // Main widget class constructor function FieldChanged(parent, field, params, setValue) { var self = this; self.field = field; // Outsource readies self.passReadies = true; self.value = params; // Create the wrapper: var $wrapper = $('<div>', { 'class': 'field h5p-editor-widget-field-changed' }); var config = self.field.fieldChanged; // var theValue = self.field.myKey; if (config === undefined) { throw new Error('You need to set the fieldChanged property in semantics.json when using the fieldChanged widget'); } H5PEditor.followField(parent, config, function () { var observedField = H5PEditor.findField(config, parent); console.log('fieldChanged event: ' + config + ' ' + observedField.value); // var targetField = H5PEditor.findField("output2", parent); // console.log(targetField); // targetField.setValue(targetField.field, "The new value!"); }); // Create the real field: var widgetName = config.widget || field.type; var fieldInstance = new H5PEditor.widgets[widgetName](parent, field, params, setValue); fieldInstance.appendTo($wrapper); /** * Add myself to the DOM * * @public * @param {H5P.jQuery} $container */ self.appendTo = function ($container) { if (!config.detach) { $wrapper.appendTo($container); } self.$container = $container; }; /** * Validate * * @public * @return {boolean} */ self.validate = function () { return fieldInstance.validate(); }; self.remove = function () {}; } return FieldChanged; })(H5PEditor.$); // Register widget H5PEditor.widgets.fieldChanged = H5PEditor.FieldChanged;Here the result:
Everything works as expected, but
- I have to attach the FieldChanged widget to another field, and tell the widget which one is to be observed, using the "fieldChanged" property,
like this:
{ "label": "The input", "name": "inputfield", "type": "text", "default": "default input", "description": "You can type text for input", "widget" : "fieldChanged", "fieldChanged" : "booleanfield", },- Only fields of type "boolean" and "select" can be observed. I need type "text".
Best,
Rudi
otacke
Wed, 02/09/2022 - 18:05
Permalink
Hi Rudi!You can get hold of
Hi Rudi!
You can get hold of any field in the semantics tree (usually by using H5PEditor.findField as in ShowWhen) that's loaded, and then you can pass your callback to the `change` function of the text widget. If you prefer, you can operate on the widget's input field, too. You can access it via the exposed jQuery variable `$input`.
Best,
Oliver
gro58
Sun, 02/06/2022 - 16:15
Permalink
Recommended method to attach an EventListener
Thank you for your quick response. I will have a look at your suggested examples.
Rudi