In a traditional PHP page, the server-side code gathers the data (e.g. from a database) and inserts it into the HTML. The browser needs to do nothing more than render the HTML it receives.
Now introduce Alpine JS to the page. Let’s say we have our data state defined like this:
Alpine.data('mydata',() => ({
student: {name: null, age: null},
course: {name: null, location: null},
}))
OK, but we want these two objects to be initialised with the student and course data from the server, so that it can be used, for example in x-show or x-bind.
We certainly don’t want to go back to the server, maybe to get the data from an API. We already got the data while the page was being built. So we need to put that data in the page somewhere that Alpine can use.
One way to do it would be for PHP to generate the data … something like:
Alpine.data('mydata',() => ({
student: <?php echo $student_object; ?>,
course: <?php echo $course_object; ?>,
}))
That would work, but often enough the data isn’t defined inline. It’s held in a standalone JS file, so it’s awkward to use PHP to fill in the gaps.
An effective solution is to provide the data as JSON, in a script element on the page. Then we just have to parse the JSON data and copy it into the Alpine data properties.
So – step 1: Generate the script element.
<?php
$student = get_student();
$course = get_course();
$jdata = [
'student' => $student,
'course' => $course,
];
?>
<script type="application/json">
<?php echo json_encode($jdata); ?>
</script>
Step 2 is to grab the script element, parse the JSON and copy over to the Alpine properties. There are plenty of ways to do this, but I wanted something I could reuse, so I put together a custom Alpine ‘x-json’ directive.
To use it, we just add x-json to the script element. In this most basic usage, the directive takes the objects it finds in the script element, and copies them over to the same-named objects in the Alpine data.
<script type="application/json" x-json>
<?php echo json_encode($jdata), PHP_EOL; ?>
</script>
In our example, this will take the student and course objects from the script, and copy them to the student and course properties in Alpine data.
The directive is capable of rather more than that, but I’ll describe it in full in Part 2.
Meantime, here’s the directive code.
document.addEventListener('alpine:init', () => {
Alpine.directive('json', (el, { expression, modifiers, value }, { evaluate }) => {
const jdata = JSON.parse(el.innerText)
if (!modifiers.length) modifiers = Object.keys(jdata)
const dest = value ? Alpine.store(value) : Alpine.$data(el)
for (let m of modifiers) {
dest[m] = jdata[m]
}
if (expression) evaluate (expression)
})
})