• Skip to main content
  • Skip to primary sidebar
Martin Taylor

Martin Taylor

PHP, CSS, MySQL and WordPress tips and techniques

Alpine

Populating Alpine data in a PHP page (part 2)

Posted on March 16, 2024

In my previous post on this topic, I described a way to transfer data into an Alpine component, if the page has been rendered by PHP on the server.

This is often going to be the situation when I’m using Alpine JS to add some interactivity to the page. For example, Alpine might need the data in an x-show condition, in an x-model input field, or to drive dynamic CSS with x-bind.

An alternative, of course, is to fetch the data from an API after the page has loaded. But this would be duplicating time and effort. PHP has already rendered the page, including the data I need, so it’s just a matter of getting the data over into the Alpine variables.

The solution I’ve devised is x-json, an Alpine custom directive. The code for the directive is in my previous post, and now I just want to give a bit more detail on its usage.

The directive is applied to a JS script element, containing JSON data, that PHP must first render into the page. Again, my previous post gave an example of how this is done, but you would end up with something like this in your page. One important note – this script must be inside the x-data scope that you want to populate.

<script type="application/json">
{"student":{"name":"Sue","age":32"},"locations":["Paris","London"]}
</script>

In this case the data is an object, consisting of two named objects. One is an object with student data, the other an array of locations. I want to put all of that data into this Alpine component:

  Alpine.data('mydata',() => ({
    student: {},
    locations: [],
  }))

Note that the names of the Alpine properties must match the names in the JSON object. I don’t see this as a serious constraint, and it keeps things simple.

Now to connect things up, I simply add the directive to the script tag:

<script type="application/json" x-json>

Now the directive will copy the JSON data into the Alpine component. Remember that the script must be placed inside the x-data scope for the component.

If for some reason I don’t want to copy all the data – say just the student object, then I add a modifier to the directive.

<script type="application/json" x-json.student>

Maybe the locations array has to go in an Alpine store, so I add another x-json directive, this time with the store name (prefixed by a colon) and a modifier.

<script type="application/json" x-json.student x-json:mystore.locations>

I can chain several modifiers together, so (if the JSON also contained a ‘lessons’ object for the Alpine store), I could do this:

<script type="application/json" x-json.student x-json:mystore.locations.lessons>

One last thing – the directive runs after the x-init and init() functions. If you need to do some processing after the JSON data arrives in the component or store, you can nominate a callback function. Maybe something like this:

<script type="application/json" x-json.student="switch()">

The ‘switch()’ function in the Alpine component will now be called after the student data is copied in. Note that if you want to use a function in an Alpine store, you have to supply the fully qualified function name. If you just supply a function name, it refers to a function in the current data component.

<script type="application/json" x-json:mystore.locations="$store.mystore.storeLoaded()">

And that’s it … for now. If I develop any new features, I’ll post them here.

Filed under: Alpine

Populating Alpine data in a PHP page (part 1)

Posted on March 2, 2024

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)
  })
})

Filed under: Alpine, PHP

Alpine JS

Posted on March 2, 2024

I’ve recently been trying out a number of JavaScript frameworks. My goal is to liven up the front-end user experience on a couple of the sites that I work on.

I got a fair way down the track with Vue.js, and was impressed with what it can do. Ultimately, though, I decided that it was slightly over the top for what I needed. I didn’t need to go to a full SPA, but Vue was leading me towards that. I could of course just use Vue’s CDN script to plug in to existing pages, but you get the best out of Vue if it’s compiled and that was getting too complicated.

I then discovered Alpine JS, which is a lightweight JS framework that delivers reactivity on the client. Alpine claims that its objective is only to supplement server-side-rendered pages, and not to replace them. In my case, having the pages built mainly in PHP and then having Alpine added to them made sense, and it works really well.

Alpine comes with a range of directives that you add to your HTML elements, and they provide a high percentage of the needs. Many of these are similar to Vue or Angular. For example, adding the x-show attribute to this div means that it will only be shown if the loginError variable is true.

<div x-show="loginError">Your user name / password were not recognised</div>

A bonus with Alpine is its extensibility, so if the out-of-box directives are not enough, it’s straightforward to define new ones with custom functionality.

I plan to post some Alpine examples, extensions and experiences here.

Filed under: Alpine

Primary Sidebar

Recent Posts

  • Populating Alpine data in a PHP page (part 2)
  • Thoughts on Tailwind CSS
  • Understanding JavaScript assignments
  • Populating Alpine data in a PHP page (part 1)
  • Alpine JS

Copyright Martin Taylor © 2025