JavaScript in Components
-
Rule: When a component requires JavaScript, it MUST be placed in a
{block script}withincore.latte. -
Reason: This keeps JavaScript logic encapsulated with its component, allows passing Latte variables to JavaScript, and enables explicit inclusion where needed on the page.
Example (core.latte with script block):
{**
* Map Component
*}
{default $latitude = 50.0755}
{default $longitude = 14.4378}
{default $zoom = 13}
{default $markers = []}
{default $uniqueId = 'default'}
{block core}
<div id="map-{$uniqueId}" class="map-component"></div>
{/block}
{block script}
<script>
(function() {
const mapConfig = {
container: 'map-{$uniqueId}',
center: [{$latitude}, {$longitude}],
zoom: {$zoom},
markers: {$markers|json}
};
document.addEventListener('DOMContentLoaded', function() {
initMap(mapConfig);
});
})();
</script>
{/block}
Including Component Scripts
-
Rule: Script blocks SHOULD be included at the end of the page, after the HTML content.
Example (Page template):
{layout '@layout.latte'}
{block content}
<h1>Contact</h1>
{include core from 'partials/components/contact-map/core.latte',
latitude => $company->lat,
longitude => $company->lng,
uniqueId => 'contact-map'
}
{/block}
{block scripts}
{include script from 'partials/components/contact-map/core.latte',
latitude => $company->lat,
longitude => $company->lng,
uniqueId => 'contact-map'
}
{/block}
Avoiding Duplicate Scripts
-
Rule: When a component may be included multiple times on a page, the script MUST handle this gracefully.
Example (Idempotent initialization):
{block script}
<script>
(function() {
// Guard against multiple executions
const instanceId = 'newsletter-{$uniqueId}';
if (window['initialized_' + instanceId]) return;
window['initialized_' + instanceId] = true;
// Component initialization...
const form = document.getElementById(instanceId);
form.addEventListener('submit', handleSubmit);
})();
</script>
{/block}
Data Attributes Alternative
-
Rule: For components used multiple times with shared logic,
data-*attributes MAY be used to pass data, with a single initialization script.
Example:
{block core}
<div class="slider"
data-autoplay="{$autoplay ? 'true' : 'false'}"
data-interval="{$interval}">
...
</div>
{/block}
{block script}
<script>
(function() {
if (window.sliderInitialized) return;
window.sliderInitialized = true;
document.querySelectorAll('.slider').forEach(function(el) {
const config = {
autoplay: el.dataset.autoplay === 'true',
interval: parseInt(el.dataset.interval, 10)
};
new Slider(el, config);
});
})();
</script>
{/block}
General JavaScript Location
-
Rule: Reusable JavaScript that is NOT component-specific MUST be placed in
resources/js/directory, not in Latte templates.
Summary:
- Component JS MUST be in
{block script}withincore.latte. - Include scripts at page end using
{include script from ...}. - Scripts MUST handle multiple instances gracefully.
- General/reusable JS belongs in
resources/js/, not in components.