Using event dispatcher in custom content type

Forums: 

Hi all, just creating a new simple custom content type to try to work out how this all works. It is just a text input filed that I want to send an xAPI statement onChange. I am a bit stuck on how to call the triggerXAPI function. This is the code:

 

var H5P = H5P || {};
 
H5P.TextInput = (function ($) {

  H5P.EventDispatcher.call(this);
  /**
   * Constructor function.
   */
  function C(options, id) {
    // Extend defaults with provided options
    this.options = $.extend(true, {}, {
      label: null
    }, options);
    // Keep provided id.
    this.id = id;
  };
 

  /**
   * Attach function called by H5P framework to insert H5P content into
   * page
   *
   * @param {jQuery} $container
   */
  C.prototype.attach = function ($container) {
    $container.addClass("h5p-textInput");
    $container.append('<div class="textInput"><label for="name">' + this.options.label + '</label><input type="text" id="name" class="userTextext" /></div>');
  };
  this.prototype = Object.create(H5P.EventDispatcher.prototype);
  this.prototype.constructor = this;
console.log('this.prototype.',this.prototype);
//this.prototype.triggerXAPI('experienced', { userText: this.name });

  return C;
})(H5P.jQuery,  H5P.EventDispatcher);

 

Which logs the attached. How do I access that function?

 

Cheers!

 

var H5P = H5P || {};
 
H5P.TextInput = (function ($, EventDispatcher) {
  /**
   * Constructor function.
   */
  function C(options, id) {
    // Extend defaults with provided options
    this.options = $.extend(true, {}, {
      label: null
    }, options);
    // Keep provided id.
    this.id = id;
    //this.prototype.attach = Object.create(H5P.EventDispatcher.prototype);
    H5P.EventDispatcher.call(this);  
  };
 
  /**
   * Attach function called by H5P framework to insert H5P content into
   * page
   *
   * @param {jQuery} $container
   */
    C.prototype = Object.create(EventDispatcher.prototype);
    C.prototype.constructor = this;
    C.prototype.attach = function ($container, EventDispatcher) {
    $container.addClass("h5p-textInput");
    $container.append('<div class="textInput"><label for="name">' + this.options.label + '</label><input type="text" id="name" class="userTextext" /></div>');
  };
  
  return C;
})(H5P.jQuery,  H5P.EventDispatcher );
(function ($, TextInput) {
  const myTextInput = new TextInput;
  console.log('myTextInput', myTextInput);
  console.log('myTextInput.triggerXAPI', myTextInput.triggerXAPI);
  H5P.externalDispatcher.on('xAPI', function (event) {
    console.log(event.data.statement);
  });
  setTimeout(()=>{myTextInput.triggerXAPI('attempted')},5000);
})(H5P.jQuery,  H5P.TextInput);
otacke's picture

Hi!

One would normally use the H5P.XAPIEvent class of H5P core to build your xAPI event including the statement as needed and then simply call `this.trigger(yourXAPIevent)` on your main instance that inherits the `trigger` function from the EventDispatcher class.

If you don't need any extras but just some statement with a particular verb (that's supported by H5P core), you can use a shortcut and use `triggerXAPI()` from the EventDispatcher class, too.

Cheers,
Oliver

Thanks Oliver, and thanks also for your tutorial series on YouTube, it was good to get started. I come from a React development environment, so this syntax is very unusual to me. Would you have an example you could point to in one of the existing Content Types that I could reverse engineer?

 

 

Edit, never mind, I found another post mentioning Tru/False as being one of the simpler ones. I'll have a look at that.

otacke's picture

Hi!

Well, it's JavaScript that you should be familiar with if you're using React :-D You're applying a wild mix of mostly ES5 (which is kind of outdated since 2015) and ES6, but that should not be relevant for calling a couple of functions. Try https://github.com/otacke/snordian-h5p-boilerplate if you need a template to instantiate some library.

TrueFalse is also old and thus using ES5, so if that confuses you (the use of "this" is confusing in ES5), you could look at some younger code. I essentially use the same helper functions in all my content types, for GameMap, I have separated the xAPI relevant functions in a mixin (think of a mixin just as some code that belongs to another class, but it's split to keep files short - so be warned that there may be references to another mixin and the main context). Essentialy, you only need to call `triggerXAPIEvent` with the verb that you need, and the other functions do the rest - you'll adapt `getXAPIDefinition` to suit your needs, however, and maybe your xAPI statement needs further properties.

What are you building by the way? Anything nice that the H5P community can play with soon?

Cheers,
Oliver

Hi Oliver, The mix of es5 and es6 is likely what is confusing me. I am familiar with JS, but I don't have a lot of experience with classes and such, and the JQuery syntax is very different to when I was using it a few years ago. In any case, I got it to work. It's just a text input field that sends xAPI data, in order to create a form and save the data to an LRS. I'm wanting to add it to Course Presentation, so that's the next step.

I will have a look at the boilerplate and your recommended library and refactor what I've already done.

I work for a startup in the financial training sector, as a very junior dev (actually the only dev atm), so imagine we will be needing to create/modify a lot of different content types. If I think it's anything that may be useful I'll be sure to share it.

 

Cheers,

Nate.

otacke's picture

Hey!

You can forget about jQuery right away. You can use it if you want to, of course, but it the only place where you need it is when communicating with H5P core that expects some function arguments to be jQuery objects - and even that will change at some point, as jQuery is supposed to be removed from H5P core. All you will need is wrapping a DOM element (or reference if your content type is written in React, that's possible as well, of course) like `H5P.jQuery(domElement: HTMLElement)`.

Using class notation (that was introduced with ES6) is really unfamiliar? I see it being used in React project all the time. Either way, it's essentially the same as in C or Java or even though JavaScript remains prototypical under the hood, so it should not be too hard to grasp and it's useful to know it beyond JavaScript.

Cheers,
Oliver

Hi Oliver!

I'm much more comfortable with the syntax in your boilerplate! This is all working now as a very basic standalone content type using a mix of the boilerplate and your GameMap content type.. The only bit I had troube with was:

registerDomElements() {
    this.setContent(this.dom);
}

Where is this being called from? Is it what actually attaches the content to the dom? I just get an error about there being no attach function or something. So instead I'm just using:

  attach(wrapper) {
    wrapper.get(0).classList.add('h5p-form');
    wrapper.get(0).appendChild(this.dom);
  }

 

Here is the repo if interested:

https://github.com/vesnathan/h5p-form-temp

Now to add it to Course Presentation....

otacke's picture

Hi!

GameMap is inheriting a couple of functions from the H5P.Question library, among them the `registerDomElements` function that wraps the `attach` function. You can use `attach` directly just as well if you don't need anything else.

Best,
Oliver