UnmanagedComponent
cdf.components. UnmanagedComponent
The UnmanagedComponent
is an advanced version of the BaseComponent
which allows control over the core CDF lifecycle for implementing components.
It should be used as the base class for all components which desire to implement an asynchronous lifecycle, as CDF cannot otherwise ensure that the postExecution
callback is correctly handled.
CDF Async Developer's Guide
CDF now supports proper, asynchronous, AJAX calls for all its querying. The following is a guide to converting old components and dashboards to the new async style, and developing new ones based on asynchronous querying.
Rationale
The first step to understanding the changes in the async patch is understanding the CDF component lifecycle. When a component is updated, the basic update lifecycle looks like this:
preExecution
-> update -> postExecution
Usually, though, there will be a call to a data source, with a subsequent call to postFetch
, and only then is the component rendered:
preExecution
-> update -> query
-> postFetch
-> redraw -> postExecution
This is a more typical lifecycle, and one that has some important limitations. First, preExecution
and postExecution
are entirely the responsibility of CDF itself, rather than the component. Because CDF has no control over the contents of the update method, it has no way of ensuring that, should the component execute an asynchronous query, postExecution
only runs after redraw. In this case, you are likely to see this instead:
preExecution
-> update -> postExecution
-> query
-> postFetch
-> redraw
This breaks the contract for postExecution
running after the component is done updating. The solution here is that the component itself must take control of postExecution
, while keeping the burden of implementing the lifecycle in CDF rather than passing it to the component developer. On a related topic, postFetch
has become a de facto standard part of the lifecycle, yet its implementation was left to the component implementers, which leads to a fairly large amount of boilerplate code.
Our objective here was to retool the base component to deal with both of these issues, thus allowing queries to be performed asynchronously while reducing the developer effort involved in creating a component.
Component Execution Order and Priority
There are no major changes in the way components behave. There is, however an important caveat: since all components that have been converted will be executed simultaneously, we can no longer rely on the order of execution.
There's now an additional property named priority
. This is the priority
of component execution, defaulting to 5. The lower the number, the higher priority
the component has. Components with the same priority
with be executed simultaneously. This property is useful in places where we need to give higher priority
to filters or other components that need to be executed before other components.
This way there's no longer the need to use dummy parameters and postChange tricks to do, for instance, cascade prompts.
Backward Compatibility and Changes
Maintaining backwards compatibility requires some care. If components have no priority
, we give them a sequential value, trying to emulate the old behavior. It's recommended that proper priorities are set in order to take advantage of the new improvements.
If using Community Dashboard Editor (CDE), note that if you edit a dashboard and save it, all components will have a default priority of 5. This may break the old behavior. If you need to change a dashboard, make sure you tweak the priorities, if needed.
Developing Components
Components desiring to use asynchronous queries should inherit from the new UnmanagedComponent
, instead of BaseComponent
. The UnmanagedComponent
base class provides pre-composed methods which implement the core lifecycle for a variety of different scenarios:
synchronous
: implements a synchronous lifecycle identical to the core CDF lifecycle.triggerQuery
: implements a simple interface to a lifecycle built around Query objects.triggerAjax
: implements a simple interface to a lifecycle built around AJAX calls.
Since all these lifecycle methods expect a callback which handles the actual component rendering, it's a conventional style to have that callback as a method of the component, called redraw
. It's also considered standard practice to use Function#bind or _.bind to ensure that, inside the redraw
callback, this
points to the component itself.
Use synchronous
If Your Component Does Not Use External Data
Components that do not use any external data at all can continue subclassing BaseComponent
without any change of functionality. However, for the sake of consistency (or because you want querying to be optional), you can use subclass UnmanagedComponent
and use the synchronous
lifecycle method to emulate BaseComponent
's behavior:
update: function() { this.synchronous(this.redraw); }
If you want to pass parameters to redraw
, you can pass them as an array to synchronous
:
update: function() { // Will call this.redraw(1, 2, 3) this.synchronous(this.redraw, [1, 2, 3]); }
Use triggerQuery
When You Want Your Component To Use CDA/Query Objects
If you're using a CDA data source, you probably want to use triggerQuery
to handle the component lifecycle for you. triggerQuery
expects at a minimum a query definition and a redraw
callback to process the query results. The query definition is an object of the form:
{ dataAccessId: 'myQuery', file: '/path/to/my/datasourceDefinition.cda' }
Typically, if you are using CDE, these properties will be added to one of either this.queryDefinition
, this.chartDefinition
or this.trafficDefinition
so you can just use this pattern:
update: function() { var redraw = _.bind(this.redraw, this); this.triggerQuery(this.queryDefinition, redraw); }
Alternating Between Static And Query-Based Data
As the lifecycle methods are completely self-contained, you can switch between them at will, deciding on an appropriate lifecycle at runtime. A common pattern (used for example in SelectComponent
and the CccComponent
family) is exposing a valuesArray
property, and using static data if valuesArray
is provided, or a query if it is not. Using UnmanagedComponent
, this convention would look like this:
update: function() { var redraw = _.bind(this.redraw, this); if(this.valuesArray && this.valuesArray.length > 0) { this.synchronous(redraw, this.valuesArray); } else { this.triggerQuery(this.queryDefinition, redraw); } }
AMD Module
require(["cdf/components/UnmanagedComponent"], function(UnmanagedComponent) { /* code goes here */ });
Extends
Constructor
Name | Description |
---|---|
new UnmanagedComponent(properties) | Advanced version of the |
Members
Name | Description |
---|---|
chartDefinition : | The chart definition |
elapsedSinceSplit : Protected | Number of milliseconds since the timer split. |
elapsedSinceStart : Protected | Number of milliseconds since the timer start. |
htmlObject : Protected | HTML element identifier where the component is rendered. |
initInstance : Deprecated Protected | The Dashboard instance to which the component belongs. |
isManaged : | Flag that defines if the component is managed or not. |
isRunning : | Flag that defines if the component is running or not. |
logColor : Protected | Color to use while logging messages. |
name : Protected | Name of the component. |
postChange : | Function to be executed after the components parameter value changes. |
preChange : | Function to be executed before the components parameter value changes. |
priority : | Priority of a component in the cdf execution cycle. |
queryDefinition : | The query definition |
timerSplit : Protected | Start date for the timer split. |
timerStart : Protected | Start date for the timer start. |
trafficDefinition : | The traffic definition |
type : Protected | Type of the component. |
visible : Protected | Visibility flag. |
Methods
Name | Description |
---|---|
_setQuery(queryDef, queryOptions) : cdf.queries.BaseQuery Protected | Creates and sets the component's current query given its definition, and optionally, query options. |
beginAjax(ajaxParameters, callback) | The beginAjax lifecycle handler implements the beginning phase of a lifecycle based on generic AJAX calls. |
beginExec() : boolean | Begins execution of the component. |
beginQuery(queryDef, callback, queryOptions) | The beginQuery lifecycle handler implements the beginning phase of a lifecycle around Query objects. |
block() | Trigger UI blocking while the component is updating. |
callCounter() : number | Increment the call counter, so we can keep track of the order in which requests were made. |
clear() | Clears the component HTML element. |
clone(parameterRemap, componentRemap, htmlRemap) : cdf.components.BaseComponent | Clones a component. |
copyEvents(target, events) | General copy events methods. |
drawTooltip() | Draws a tooltip, if one is defined in the component options. |
endExec() | Ends a successful execution of the component. |
error(msg, cause) | Triggers an error event on the component. |
errorNotification(err, ph) | Creates an error notification |
execute(callback) | Generic execute method that handles |
failExec(arg) | Fails execution of the component, given an error object or the arguments of a jQuery.ajax error callback. |
focus() | Focus the first placeholder DOM element on the component. |
getAddIn(slot, addIn) : cdf.AddIn | Gets an add-in for this component. |
getAddInOptions(slot, addIn) : object | Gets an add-in option. |
getErrorHandler() : cdf.components.UnmanagedComponent | Gets an error handler suitable for use as a jQuery.ajax error callback or a try/catch handler. |
getQueryDefinition() : Object | undefined | Gets the query definition |
getSuccessHandler(counter, success, always, canceled) : function | Builds a generic response handler which runs the success callback. |
getValuesArray() : Array.<<code>object > Deprecated | Gets the values array property. |
hasAddIn(slot, addIn) : boolean | Returns |
isSilent() : boolean | Returns |
parseArray(jData, includeHeader) : Array.<<code>object > Deprecated | Builds an array with the data received from the server in another format. |
parseArrayCda(jData, includeHeader) : Array.<<code>object > Deprecated | Builds an array with the data received. |
placeholder(selector) : jQuery | Getter for the component's DOM element. |
postExec() | Handles calling |
postFetchData(data) : object | Handles calling |
preExec() : boolean | Handles calling |
setAddInOptions(slot, addIn, options) | Sets the options for an add-in. |
showTooltip() | Shows a tooltip attached to the component, if one is defined in the |
synchronous(callback, arg) | The synchronous lifecycle handler closely resembles the core CDF lifecycle. |
triggerAjax(url, params, callback, ajaxParameters) | The triggerAjax lifecycle handler builds a lifecycle around generic AJAX calls. |
triggerQuery(queryDef, callback, queryOptions) | The triggerQuery lifecycle handler builds a lifecycle around Query objects. |
unblock() | Trigger UI unblock when the component finishes updating. |
Events
Name | Description |
---|---|
cdf:error | Event triggered on error. |
cdf:postExecution | Event triggered after execution. |
cdf:postFetch(data) | Event triggered after fetching data. |
cdf:preExecution | Event triggered before execution. |
cdf:render | Event triggered after the |
all | Event triggered by any other event. |
Constructor Details
new UnmanagedComponent(properties) | ||||||
---|---|---|---|---|---|---|
The constructor of an unmanaged component. Source: components/UnmanagedComponent.js, line 21
|
Members Details
chartDefinition: |
---|
The chart definition Source: components/UnmanagedComponent.js, line 228 See also: |
elapsedSinceSplit: Protected |
---|
Number of milliseconds since the timer split. Source: components/BaseComponent.js, line 98 Inherited From: cdf.components.BaseComponent#elapsedSinceSplit Default Value: -1 |
elapsedSinceStart: Protected |
---|
Number of milliseconds since the timer start. Source: components/BaseComponent.js, line 108 Inherited From: cdf.components.BaseComponent#elapsedSinceStart Default Value: -1 |
htmlObject: Protected |
---|
The HTML element identifier, unique in the HTML page, where the component is rendered. Source: components/BaseComponent.js, line 46 Inherited From: cdf.components.BaseComponent#htmlObject |
initInstance: Deprecated Protected |
---|
The Dashboard instance to which the component belongs. Source: components/BaseComponent.js, line 120 Inherited From: cdf.components.BaseComponent#initInstance |
isManaged: |
---|
Flag that defines if the component is managed or not. Source: components/UnmanagedComponent.js, line 198 Default Value: false Overrides: cdf.components.BaseComponent#isManaged |
isRunning: |
---|
Flag that defines if the component is running or not. Source: components/UnmanagedComponent.js, line 207 Default Value: false |
logColor: Protected |
---|
Color to use while logging messages. Source: components/BaseComponent.js, line 118 Inherited From: cdf.components.BaseComponent#logColor Default Value: undefined |
name: Protected |
---|
The name of the component. Its name needs to be unique in the dashboard to which they belong. Source: components/BaseComponent.js, line 30 Inherited From: cdf.components.BaseComponent#name |
postChange: |
---|
Function to be executed after the components parameter value changes. Source: components/BaseComponent.js, line 140 Inherited From: cdf.components.BaseComponent#postChange |
preChange: |
---|
Function to be executed before the components parameter value changes. Source: components/BaseComponent.js, line 131 Inherited From: cdf.components.BaseComponent#preChange |
priority: |
---|
Priority of a component in the cdf execution cycle. Source: components/UnmanagedComponent.js, line 209 Default Value: 5 |
queryDefinition: |
---|
The query definition |
timerSplit: Protected |
---|
Start date for the timer split. Source: components/BaseComponent.js, line 88 Inherited From: cdf.components.BaseComponent#timerSplit Default Value: 0 |
timerStart: Protected |
---|
Start date for the timer start. Source: components/BaseComponent.js, line 78 Inherited From: cdf.components.BaseComponent#timerStart Default Value: 0 |
trafficDefinition: |
---|
The traffic definition Source: components/UnmanagedComponent.js, line 238 See also: |
type: Protected |
---|
The type of the component, usually the class name of the component. Source: components/BaseComponent.js, line 38 Inherited From: cdf.components.BaseComponent#type |
visible: Protected |
---|
Visibility flag. Source: components/BaseComponent.js, line 56 Inherited From: cdf.components.BaseComponent#visible Default Value: true |
Methods Details
_setQuery(queryDef, queryOptions) : cdf.queries.BaseQuery Protected | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Creates and sets the component's current query given its definition, and optionally, query options. Source: components/UnmanagedComponent.js, line 649
|
beginAjax(ajaxParameters, callback) | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
The beginAjax lifecycle handler implements the beginning phase of a lifecycle based on generic AJAX calls. It implements the lifecycle: Ending the execution is the responsibility of the specified callback, by calling endExec , resulting in: Source: components/UnmanagedComponent.js, line 620
|
beginExec() : boolean | ||||
---|---|---|---|---|
Begins execution of the component. This method handles calling A component that actually begins execution, by returning Source: components/UnmanagedComponent.js, line 369
|
beginQuery(queryDef, callback, queryOptions) | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
The beginQuery lifecycle handler implements the beginning phase of a lifecycle around Query objects. It implements the lifecycle: Ending the execution, is the responsibility of the specified callback by calling Source: components/UnmanagedComponent.js, line 518
|
block() |
---|
Trigger UI blocking while the component is updating. Default implementation uses the global CDF blockUI, but implementers are encouraged to override with per-component blocking where appropriate (or no blocking at all in components that support it). |
callCounter() : number | ||||
---|---|---|---|---|
Increment the call counter, so we can keep track of the order in which requests were made. Source: components/UnmanagedComponent.js, line 672
|
clear() |
---|
Clears the component HTML element. Source: components/BaseComponent.js, line 204 Inherited From: cdf.components.BaseComponent#clear |
clone(parameterRemap, componentRemap, htmlRemap) : cdf.components.BaseComponent | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Clones a component. Source: components/BaseComponent.js, line 235 Inherited From: cdf.components.BaseComponent#clone
|
copyEvents(target, events) | |||||||||
---|---|---|---|---|---|---|---|---|---|
General copy events methods. Given a target component and an event list, adds the component as a listener for all events in the list. Source: components/BaseComponent.js, line 216 Inherited From: cdf.components.BaseComponent#copyEvents
|
drawTooltip() |
---|
Draws a tooltip, if one is defined in the component options. |
endExec() |
---|
Ends a successful execution of the component. This method handles drawing and showing the component's tooltip, if any, calling |
error(msg, cause) | |||||||||
---|---|---|---|---|---|---|---|---|---|
Triggers an error event on the component. Takes as arguments the error message and optionally, a Source: components/UnmanagedComponent.js, line 756
Fires: cdf.event:cdf , cdf.components.UnmanagedComponent#event:cdf:error |
errorNotification(err, ph) | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Creates an error notification Source: components/UnmanagedComponent.js, line 782
See also: |
execute(callback) | ||||||
---|---|---|---|---|---|---|
Generic execute method that handles The specified This method is sugar for the following common pattern: Source: components/UnmanagedComponent.js, line 445
|
failExec(arg) | ||||||
---|---|---|---|---|---|---|
Fails execution of the component, given an error object or the arguments of a jQuery.ajax error callback. This method handles parsing, signaling and logging of the error and unblocking the UI, if necessary. Source: components/UnmanagedComponent.js, line 386
|
focus() |
---|
Focus the first placeholder DOM element on the component. Source: components/BaseComponent.js, line 180 Inherited From: cdf.components.BaseComponent#focus |
getAddIn(slot, addIn) : cdf.AddIn | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Gets an add-in for this component. Source: components/BaseComponent.js, line 295 Inherited From: cdf.components.BaseComponent#getAddIn
|
getAddInOptions(slot, addIn) : object | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Gets an add-in option. Source: components/BaseComponent.js, line 505 Inherited From: cdf.components.BaseComponent#getAddInOptions
|
getErrorHandler() : cdf.components.UnmanagedComponent | ||||
---|---|---|---|---|
Gets an error handler suitable for use as a jQuery.ajax error callback or a try/catch handler. This method returns a Source: components/UnmanagedComponent.js, line 740
|
getQueryDefinition() : Object | undefined | ||||
---|---|---|---|---|
Gets the query definition The properties used for retrieving the query definition are based on the known component implementations. Source: components/UnmanagedComponent.js, line 557
|
getSuccessHandler(counter, success, always, canceled) : function | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Builds a generic response handler which runs the success callback when being called in response to the most recent AJAX request that was triggered for this component (as determined by comparing counter and this.runCounter), and always calls the always callback. If the counter is not provided, it will be generated automatically. Accepts the following calling conventions:
Source: components/UnmanagedComponent.js, line 697
|
getValuesArray() : Array.<<code>object > Deprecated | ||||
---|---|---|---|---|
Gets the values array property, if one is defined. Otherwise, issues a call to the server to get data. Source: components/BaseComponent.js, line 329 Inherited From: cdf.components.BaseComponent#getValuesArray
|
hasAddIn(slot, addIn) : boolean | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Returns Source: components/BaseComponent.js, line 312 Inherited From: cdf.components.BaseComponent#hasAddIn
|
isSilent() : boolean | ||||
---|---|---|---|---|
Returns Source: components/UnmanagedComponent.js, line 825
|
parseArray(jData, includeHeader) : Array.<<code>object > Deprecated | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Builds an array with the data received from the server in another format. Source: components/BaseComponent.js, line 403 Inherited From: cdf.components.BaseComponent#parseArray
|
parseArrayCda(jData, includeHeader) : Array.<<code>object > Deprecated | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Builds an array with the data received from the server in CDA format. Source: components/BaseComponent.js, line 446 Inherited From: cdf.components.BaseComponent#parseArrayCda
|
placeholder(selector) : jQuery | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
Getter for the component's DOM element. Returns the jQuery Source: components/BaseComponent.js, line 171 Inherited From: cdf.components.BaseComponent#placeholder
|
postExec() |
---|
Handles calling All components extending UnmanagedComponent should either use one of the three lifecycles declared in this class ( Source: components/UnmanagedComponent.js, line 299 Fires: cdf.event:cdf , cdf.components.UnmanagedComponent#event:cdf:postExecution |
postFetchData(data) : object | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
Handles calling Source: components/UnmanagedComponent.js, line 318
Fires: cdf.event:cdf , cdf.components.UnmanagedComponent#event:cdf:postFetch
|
preExec() : boolean | ||||
---|---|---|---|---|
Handles calling All components extending UnmanagedComponent should either use one of the three lifecycles declared in this class ( Source: components/UnmanagedComponent.js, line 264 Fires: cdf.event:cdf , cdf.components.UnmanagedComponent#event:cdf:preExecution
|
setAddInOptions(slot, addIn, options) | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Sets the options for an add-in. Source: components/BaseComponent.js, line 486 Inherited From: cdf.components.BaseComponent#setAddInOptions
|
showTooltip() |
---|
Shows a tooltip attached to the component, if one is defined in the |
synchronous(callback, arg) | |||||||||
---|---|---|---|---|---|---|---|---|---|
The synchronous lifecycle handler closely resembles the core CDF lifecycle, and is provided as an alternative for components that desire the option to alternate between a synchronous and asynchronous style lifecycles depending on external configuration (e.g., if it can take values from either a static array or a query). It takes the component drawing method as a callback. Source: components/UnmanagedComponent.js, line 466
|
triggerAjax(url, params, callback, ajaxParameters) | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
The triggerAjax lifecycle handler builds a lifecycle around generic AJAX calls. It implements the lifecycle: After the call to the
In the second case, you can add any other jQuery.ajax parameters you desire to the object, but Source: components/UnmanagedComponent.js, line 586
Fires: cdf.event:cdf , cdf.components.UnmanagedComponent#event:cdf:render |
triggerQuery(queryDef, callback, queryOptions) | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
The triggerQuery lifecycle handler builds a lifecycle around Query objects. Execution ends immediately after the call to the specified callback. It takes a query definition object which is passed directly into the Query constructor, and the component rendering callback, and implements the lifecycle: This method detects concurrent updates to the component and ensures that only the redraw of the most recent update is performed. Source: components/UnmanagedComponent.js, line 498
|
unblock() |
---|
Trigger UI unblock when the component finishes updating. Functionality is defined as undoing whatever was done in the block method. Should also be overridden in components that override |
Events Details
cdf:error |
---|
Event triggered when an error occurs. |
cdf:postExecution |
---|
Event triggered after a component finishes executing. |
cdf:postFetch(data) | ||||||
---|---|---|---|---|---|---|
Event triggered after an Source: components/_doc/events.jsdoc, line 54
|
cdf:preExecution |
---|
Event triggered before a component starts executing. |
cdf:render |
---|
Event triggered after the |
all |
---|
The Source: components/_doc/events.jsdoc, line 19 Inherited From: cdf.components.BaseComponent#event:all See also: Backbone Events catalog. |