Client-side Components
Client-side components are implemented using Web Components. Although you can implement your Web Components anyway you like, we favor the use of Polymer which offers a lot of high level goodies, such as declarative declaration syntax and data-binding.
Compatibility checklist
The following checklist describes the minimum recommended interfaces and conventions that ASQ elements should support:
- Naming convention. The naming convention is to start with
asq-q
. If it’s a question type, finish with-q
. - Behaviors. implement
asqElementBehavior
orasqQuestionElementBehavior
. - Roles. Internally have a different element for each role
- [
value
property]. (question type elements only). <asq-solution>
element support. (question type elements only).
Naming conventions
It’s advised that all ASQ plugins start with asq-
. In addition, question type elements should end in -q
.
Examples
Non-question elements:asq-canvas
, asq-welcome
.
Question types:
asq-multi-choice-q
, asq-highlight-q
.
Behaviors
The asq-base element contains a set of base behaviors that each asq-element should implement. These behaviors add role
support, uid
property, whether the element is a question element and more. Depending on whether your ASQ element is a plain element or a question type element you should use asqElementBehavior
or asqQuestionElementBehavior
respectively.
Example
1 | <link rel="import" href="../polymer/polymer.html"> |
Roles
Each client-side component is encapsulated in a root Custom HTML Element. It may display different UI and support different functionality depending on the role of the user. To simplify this task it’s wise to separate complex components int sub-components by role. The root custom element is responsible for rendering the appropriate role-based sub-component.
Example
1 | <link rel="import" href="../polymer/polymer.html"> |
Notice the use of hasRole()
which is defined in asqElementBehavior
from asq-base.html
and the use of restamp="true"
to avoid having both role elements in the DOM. For more on restamp
have a look at Polymer documentation.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../asq-base/asq-base.html">
<dom-module id="asq-my-question-type-q-viewer">
<template>
<h2>This is the <em>viewer</em> element for <asq-my-question-type-q> </h2>
</template>
<script>
Polymer({
is: "asq-my-question-type-q-viewer",
behaviors: [
ASQ.asqQuestionElementBehavior
],
});
</script>
</dom-module>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../asq-base/asq-base.html">
<dom-module id="asq-my-question-type-q-presenter">
<template>
<h2>This is the <em>presenter</em> element for <asq-my-question-type-q> </h2>
</template>
<script>
Polymer({
is: "asq-my-question-type-q-presenter",
behaviors: [
ASQ.asqQuestionElementBehavior
],
});
</script>
</dom-module>
value
property (question type elements only)
Each question type should have a value
property that represents the current answer of a viewer. To easily set the value of a question to the value of the solution, this property should be compatible with the format of the solution that is specified in the <asq-solution>
element inside each question type element.
<asq-solution>
element support
During authoring, in question-type elements that support a solution, the solution should be provided within one <asq-solution>
element. Multiple JSON.stringify
on. The <asq-solution>
element should be stripped off from the server-side component during the parse-html
hook. IT SHOULD NOT BE SERVED to the clients. Instead, when the solution is needed, it can be pulled from the server with the appropriate events.
1 | <asq-my-question-type-q> |
Communication
PubSub
Components can listen for the asq-ready
event which will provide them with an eventbus which can be used for communication with the “core” client app. Normally you will do something like this on your root component element:1
2
3document.addEventListener('asq-ready', function (evt) {
this.eventBus = evt.detail.asqEventBus
}.bind(this));
and then pass via data-binding the eventBus
to the role-specific elements.
1 | <dom-module id="asq-my-question-type-q"> |
Then you can consume events as follows:
1 | this.eventBus.on('asq:question_type', cb); |
where cb
is a callback function to call when the asq:question_type
event occurs.