Alpine CSP example
Currently Hyvä CSP is unreleased
This is a documentation preview.
Please watch the #update-notifications channel in Slack to be notified when it is available.
Before we cover each difference in detail, here is an example component illustrating most differences.
<?php
$items = [
['name' => 'Foo', 'type' => 'a'],
['name' => 'Bar', 'type' => 'b'],
['name' => 'Buz', 'type' => 'c'],
['name' => 'Moo', 'type' => 'd'],
['name' => 'Qux', 'type' => 'c'],
['name' => 'Biz', 'type' => 'b'],
];
?>
<div x-data="exampleCspComponent"
data-items="<?= $escaper->escapeHtmlAttr(json_encode($items))?>">
<button type="button" class="btn" @click="toggle">Click</button>
<span x-text="isActive"></span>
<template x-if="isActive">
<div>Hello</div>
</template>
<template x-if="isNotActive">
<div>Bye</div>
</template>
<ul>
<form>
<label for="example">Input without x-model</label>
<input type="text"
id="example"
@input="onInput"
:value="value">
</form>
<template x-for="(item, index) in items">
<li @click="registerClick" :class="listItemClasses">
<span x-text="index">y</span>:
<span x-text="item.name"></span>
</li>
</template>
</ul>
</div>
<script>
// Declare the function in "global" scope, so it can be customized.
function exampleCspComponent() {
return {
isActive: true,
items: [],
value: '',
init() {
// Passing arguments is done via dataset attributes.
this.items = JSON.parse(this.$root.dataset.items)
},
isNotActive() {
// Transforming a value has to be done in a method.
return ! this.isActive;
},
toggle() {
// Mutations are done in methods
this.isActive = !this.isActive;
},
listItemClasses() {
// In x-for loops the vars become properties on the "this" object.
return {
'border-gray-200': this.index % 2,
'border': this.index % 2,
'bg-red-500': this.item.name === 'Buz'
}
},
onInput() {
this.value = this.$event.target.value;
},
registerClick() {
// Iteration context vars are preserved in method calls in Alpine CSP, just like regular Alpine.
console.log(this.index)
},
};
}
(() => {
// Ensure that:
// - the constructor function is not called before Alpine is initialized
// - it is also called if it is added to the page after Alpine is ready
// (Hyvä will have a convenience method for this)
const initFn = () => Alpine.data('exampleCspComponent', exampleCspComponent);
window.Alpine ? initFn() : window.addEventListener('alpine:init', initFn, {once: true})
})()
</script>