BETA We're building something new — all help is welcome! Contribute →

#[Json]

Return data directly to the client without re-rendering the component.

Basic Usage

Mark a method with #[Json] to return data directly to JavaScript. The method's return value becomes available as a Promise result.

use LiVue\Attributes\Json;

class ProductSearch extends Component
{
    public string $query = '';

    #[Json]
    public function search(string $term): array
    {
        return Product::where('name', 'like', "%{$term}%")
            ->take(10)
            ->get(['id', 'name', 'price'])
            ->toArray();
    }

    #[Json]
    public function getStats(): array
    {
        return [
            'total' => Product::count(),
            'active' => Product::where('active', true)->count(),
        ];
    }
}

Using in Templates

The livue.call() method returns a Promise when calling a #[Json] method.

<div>
    <input v-model="query" placeholder="Search...">

    <button @click="livue.call('search', [query]).then(data => livue.set('results', data))">
        Search
    </button>

    <ul>
        <li v-for="item in results">
            {{ item.name }} - ${{ item.price }}
        </li>
    </ul>
</div>

Using with @script

Combine with @script for cleaner async handling:

<button @click="handleSearch">Search</button>

@script
const handleSearch = async () => {
    const results = await livue.call('search', [state.query]);
    state.results = results;

    // Do something with the results
    if (results.length === 0) {
        alert('No results found');
    }
};
@endscript

#[Json] vs #[Renderless]

Both skip re-rendering, but they serve different purposes:

Attribute State Updated Returns Data Use Case
#[Renderless] Yes No Actions that change state
#[Json] No Yes Fetching data

Use Cases

Autocomplete

Fetch suggestions as the user types without full re-renders.

Infinite Scroll

Load more items and append them to an existing list.

Form Validation

Check uniqueness or validate data server-side.

Data Export

Fetch data for client-side CSV generation or processing.

Error Handling

Handle errors using standard Promise catch or try/catch with async/await:

// Promise .catch()
livue.call('search', [query])
    .then(data => { /* handle success */ })
    .catch(err => { console.error('Search failed:', err); });

// async/await
try {
    const data = await livue.call('search', [query]);
} catch (err) {
    console.error('Search failed:', err);
}