Created
February 16, 2017 12:59
-
-
Save tistre/dcbf491ca86b7526228e4466bc515aae to your computer and use it in GitHub Desktop.
Simplistic JavaScript component architecture demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* A sample "Die" component using the "library" */ | |
/** | |
* Create a "Die" component instance | |
* | |
* Creates an anonymous object you can only interact with using events. | |
* | |
* @param object config componentConfig.config object from the component JSON data | |
* @constructor | |
*/ | |
Dcc.Components.Die = function (config) | |
{ | |
var _private = {}; | |
_private.config = config; | |
_private.$element = $(_private.config.selector); | |
/* Component creation and removal */ | |
/** | |
* Event listener configuration | |
*/ | |
_private.getEventListeners = function () | |
{ | |
return [ | |
[_private.$element, 'click', 'button', _private.onRollButtonClick], | |
[_private.$element, 'DccRoll', _private.onRollButtonClick] | |
]; | |
}; | |
/** | |
* On component creation, add event listeners | |
*/ | |
_private.onCreateComponent = function () | |
{ | |
Dcc.addEventListeners(_private.getEventListeners()); | |
/* Example for custom component events others can listen to */ | |
_private.$element.trigger($.Event | |
( | |
'DccRolled', | |
{ | |
DccParams: { | |
pips: _private.config.pips, | |
componentId: _private.config.selector.substr(1) | |
} | |
} | |
)); | |
}; | |
/** | |
* On component removal (after Ajax reload), remove event listeners | |
*/ | |
_private.onRemoveComponent = function () | |
{ | |
Dcc.removeEventListeners(_private.getEventListeners()); | |
}; | |
/* Implementation */ | |
_private.onRollButtonClick = function (e) | |
{ | |
_private.reload(); | |
}; | |
_private.reload = function () | |
{ | |
$.get(_private.config.ajaxUrl, _private.onReloadData); | |
}; | |
_private.onReloadData = function (html) | |
{ | |
_private.onRemoveComponent(); | |
Dcc.replaceInnerHtmlAndCreateComponents(_private.$element, html); | |
}; | |
_private.onCreateComponent(); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Core "library" functions */ | |
var Dcc = Dcc || {}; | |
Dcc.Components = Dcc.Components || {}; | |
/** | |
* Initialize by creating components from all script elements with JSON data | |
*/ | |
Dcc.init = function () | |
{ | |
Dcc.createComponentsFromScriptElements($('script[type="application/json"]')); | |
$(document).trigger('Dcc_Initialized'); | |
}; | |
/** | |
* Create components from script elements with JSON data | |
* | |
* @param object[] $scriptElements jQuery set of script elements containing JSON data | |
*/ | |
Dcc.createComponentsFromScriptElements = function ($scriptElements) | |
{ | |
$scriptElements.each(function (i, scriptElement) | |
{ | |
Dcc.createComponentFromScriptElement(scriptElement); | |
}); | |
}; | |
/** | |
* Create a component from a script element with JSON data | |
* | |
* @param DOMElement scriptElement Script element containing JSON data | |
*/ | |
Dcc.createComponentFromScriptElement = function (scriptElement) | |
{ | |
var jsonData; | |
try { | |
jsonData = JSON.parse(scriptElement.innerHTML); | |
} catch (e) { | |
console.log(e); | |
return; | |
} | |
if (jsonData.createComponent === undefined) { | |
return; | |
} | |
Dcc.createComponent(jsonData.createComponent); | |
}; | |
/** | |
* Create a component | |
* | |
* Calls the given factoryFunction with the given config to create a component instance (an anonymous object). | |
* | |
* @param object componentConfig Object (with factoryFunction and config properties) from component JSON data | |
*/ | |
Dcc.createComponent = function (componentConfig) | |
{ | |
var factoryFunction; | |
if ((componentConfig.factoryFunction === undefined) || (componentConfig.config === undefined)) { | |
return; | |
} | |
if (Dcc.Components[componentConfig.factoryFunction] === undefined) { | |
console.log('ERROR: Dcc.Components["' + componentConfig.factoryFunction + '"] is undefined, cannot create component:', componentConfig); | |
return; | |
} | |
factoryFunction = Dcc.Components[componentConfig.factoryFunction]; | |
if (typeof factoryFunction !== 'function') { | |
console.log('ERROR: Dcc.Components["' + componentConfig.factoryFunction + '"] is not a function, cannot create component:', componentConfig); | |
return; | |
} | |
factoryFunction(componentConfig.config); | |
}; | |
/** | |
* Replace innerHTML and create components from JSON data | |
* | |
* @param object $element jQuery element whose innerHTML to replace | |
* @param string html The HTML whose innerHTML to replace with | |
*/ | |
Dcc.replaceInnerHtmlAndCreateComponents = function ($element, html) | |
{ | |
var $html; | |
if ($.type(html) !== 'string') { | |
return; | |
} | |
html = $.trim(html); | |
if (html.length === 0) { | |
return; | |
} | |
$html = $(html); | |
$element.empty().append($html.children()); | |
Dcc.createComponentsFromScriptElements($element.find('script[type="application/json"]')); | |
}; | |
/** | |
* Add event listeners | |
* | |
* @param array eventListeners Array of arrays of jQuery element plus $.on() parameters | |
*/ | |
Dcc.addEventListeners = function (eventListeners) | |
{ | |
eventListeners.forEach(function (params) | |
{ | |
var $element = params.shift(); | |
$element.on.apply($element, params); | |
}); | |
}; | |
/** | |
* Remove event listeners | |
* | |
* @param array eventListeners Array of arrays of jQuery element plus $.on() parameters | |
*/ | |
Dcc.removeEventListeners = function (eventListeners) | |
{ | |
eventListeners.forEach(function (params) | |
{ | |
var $element = params.shift(); | |
$element.off.apply($element, params); | |
}); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Return the HTML for a "Die" component instance | |
* | |
* @param string $componentId | |
*/ | |
function getDieComponentHtml($componentId) | |
{ | |
$pips = rand(1, 6); | |
?> | |
<div id="<?= htmlspecialchars($componentId) ?>" style="padding: 10px;"> | |
<h1>Die <i><?= htmlspecialchars($componentId) ?></i></h1> | |
<!-- Some random number --> | |
<div style="background-color: yellow;"><?= $pips ?></div> | |
<!-- Button for Ajax reload, click handler assigned in Dcc.Components.Die() --> | |
<button>Roll</button> | |
<!-- JSON data for JavaScript object creation, used by Dcc.createComponentFromScriptElement() --> | |
<script type="application/json"><?= json_encode([ | |
'createComponent' => [ | |
'factoryFunction' => 'Die', | |
'config' => [ | |
'selector' => '#' . $componentId, | |
'ajaxUrl' => $_SERVER['PHP_SELF'] . '?getComponentAjax=' . urlencode($componentId), | |
'pips' => $pips | |
] | |
] | |
]) ?></script> | |
</div> | |
<?php | |
} | |
if (! empty($_REQUEST['getComponentAjax'])) { | |
if (in_array($_REQUEST['getComponentAjax'], ['die1', 'die2'])) { | |
echo getDieComponentHtml($_REQUEST['getComponentAjax']); | |
exit; | |
} | |
} | |
?> | |
<html> | |
<head> | |
<title>Simple JavaScript component architecture demo</title> | |
</head> | |
<body> | |
<div style="display: flex;"> | |
<?= getDieComponentHtml('die1') ?> | |
<?= getDieComponentHtml('die2') ?> | |
</div> | |
<div id="winnerMsg">Loading…</div> | |
<div> | |
<button id="rollBothButton">Roll both</button> | |
</div> | |
<script | |
src="https://code.jquery.com/jquery-3.1.1.min.js" | |
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" | |
crossorigin="anonymous"></script> | |
<script src="js-component-demo-dcc-library.js" type="text/javascript"></script> | |
<script src="js-component-demo-dcc-components.js" type="text/javascript"></script> | |
<script type="text/javascript"> | |
/* Page specific functionality */ | |
var pips = {die1: undefined, die2: undefined}; | |
function updateWinnerMessage() | |
{ | |
var msg; | |
if ((pips.die1 === undefined) || (pips.die2 === undefined)) { | |
msg = 'Unknown'; | |
} | |
else if (pips.die1 > pips.die2) { | |
msg = 'die1 wins!'; | |
} | |
else if (pips.die1 < pips.die2) { | |
msg = 'die2 wins!'; | |
} | |
else { | |
msg = 'Draw.'; | |
} | |
$('#winnerMsg').html(msg); | |
} | |
function onRolled(e) | |
{ | |
pips[e.DccParams.componentId] = e.DccParams.pips; | |
updateWinnerMessage(); | |
} | |
/* Example for sending a message to a component using a custom event */ | |
function rollBoth() | |
{ | |
$('#die1').trigger('DccRoll'); | |
$('#die2').trigger('DccRoll'); | |
} | |
/* Initialize */ | |
$(document).ready(function () | |
{ | |
/* Example for listening to a custom component event */ | |
$('#die1').on('DccRolled', onRolled); | |
$('#die2').on('DccRolled', onRolled); | |
Dcc.init(); | |
$('#rollBothButton').on('click', rollBoth); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment