4

I have an array of messages being pulled into view thanks to Laravel Echo, Livewire, and AlpineJS.

<div class="mt-4 rounded-lg p-6"
    x-data="{{ json_encode(['messages' => $messages, 'messageBody' => '']) }}"
    x-init="
        Echo.join('demo')
        .listen('MessageSentEvent', (e) => {
            @this.call('incomingMessage', e)
        })
">
    <template x-if="messages.length > 0"> 
        <template
            x-for="message in messages"
            :key="message.id"
        >
            <div class="my-8">
                <div class="flex flex-row justify-between border-b border-gray-200">
                    <span class="text-white-600 chat-block-author"  x-text="message.user.name"></span>: <span class="text-white-800" x-text="message.body" style="margin-left:10px;"></span>
                </div>
            </div>
        </template>
    </template>
</div>

I want to dynamically add a class called chat-block-author when the rendered message belongs to the logged-in user. The Message model does contain user_id for each item, but I can't seem to get AlpineJS to play well with conditional logic like I could with Blade.

Any tips?

This does not work

<template x-if="message.user_id == {{ Auth::user()->id }}">
    <div class="my-8">
        <div class="flex flex-row justify-between border-b border-gray-200">
            <span class="text-white-600 chat-block-author"  x-text="message.user.name"></span>: <span class="text-white-800" x-text="message.body" style="margin-left:10px;"></span>
        </div>
    </div>
</template>

as it produces this error

Uncaught (in promise) ReferenceError: message is not defined
    at eval (eval at tryCatch.el.el (alpine.js?df24:1), <anonymous>:3:36)
    at tryCatch.el.el (alpine.js?df24:140)
    at tryCatch (alpine.js?df24:127)
    at saferEval (alpine.js?df24:135)
    at Component.evaluateReturnExpression (alpine.js?df24:1747)
    at eval (alpine.js?df24:1714)
    at Array.forEach (<anonymous>)
    at Component.resolveBoundAttributes (alpine.js?df24:1696)
    at Component.updateElement (alpine.js?df24:1672)
    at eval (alpine.js?df24:1628)
markusp
  • 329
  • 1
  • 2
  • 10

1 Answers1

14

You did not mention where you want to add that class to, but in AlpineJS you can dynamically assign any attribute including classes by doing something like this:

<div :class="{ 'chat-block-author': message.user_id === {{ Auth::user()->id }} }" class="your-other-classes go-here">
    ...
</div>

Note that you can also use it with an existing class attribute, the attributes defined in :class are dynamically added to your class attribute if the specified condition is true.

Lupinity Labs
  • 2,099
  • 1
  • 15
  • 23
  • In this case I think there might be the additional issue of `{{ Auth::user()->id }}` not being a string? So possibly would need `"{{ Auth::user()->id }}"` – Hugo Jan 31 '21 at 11:18
  • `message.user_id` is not a string either, so why should we turn `Auth::user()->id` into a string? If we did, the `===` operator would fail, as both need to be of the same type. – Lupinity Labs Jan 31 '21 at 11:20
  • @Hugo I just realized you might not be familiar with Laravel and the Blade template engine, so I'll have to add that {{ Auth::user()->id }} is Blade syntax and will be replaced in whole by the value of the PHP expression inside of the brackets. – Lupinity Labs Jan 31 '21 at 11:23
  • 1
    It is worth noting that the above syntax will break when a guest user browses the page, so this should only be used on pages behind auth, or should be extended to something like `{{ Auth::user()?->id ?? 0 }}`. – Lupinity Labs Jan 31 '21 at 11:25
  • Remember that if the value is not an integer to add quotes. ie `'{{ Auth::user()->name }}'` – Jed Lynch Feb 15 '22 at 23:26
  • @JedLynch my favorite way of taking care of those things is to use the `@js` blade directive, which will appropriately convert any value from PHP to a Javascript notation. – Lupinity Labs Jul 17 '22 at 14:37