<p>I can think of a couple of simple ways to output an entry's properties on a click event. If there aren't too many of them, you could output the properties that you want as data attributes on the link/button element in your Twig template, then access them from a JS <code>click</code> event handler:</p>
<pre><code>{# Twig template #}
&lt;a href=&quot;someUrl&quot;
    class=&quot;myLink&quot;
    data-title=&quot;{{ entry.title }}&quot; 
    data-custom-property=&quot;{{ entry.customProperty }}&quot;&gt;
    Link text
&lt;/a&gt;

// JavaScript code
const myLink = document.querySelector('a.myLink');
myLink.addEventListener('click', function() {
    // Get properties
    const title = myLink.getAttribute('data-title');
    const customProperty = myLink.getAttribute('data-custom-property');
});
</code></pre>
<p>That's probably the simplest method. If you want to access a lot of properties, you could output them into a JavaScript global variable in your Twig template and access them that way, but that can be messy and pollute the global JS scope.</p>
<p>If you want to get more advanced, the <a href="https://plugins.craftcms.com/element-api" rel="nofollow noreferrer">Element API</a> plugin is the next step. This allows you to create endpoints that you can access via XHR/fetch requests, which return JSON data that you specify. See <a href="https://github.com/craftcms/element-api#setup" rel="nofollow noreferrer">here</a> for an example of how the Element API works.</p>
<p>Using the Element API, your click event handler could fetch the entry's JSON data and output it dynamically as needed. You'd have something like this in your <code>config/element-api.php</code> config file:</p>
<pre><code>&lt;?php

use craft\elements\Entry;

return [
    'endpoints' =&gt; [
        'api/entries/all.json' =&gt; function() {
            return [
                'elementType' =&gt; Entry::class,
                'criteria' =&gt; ['section' =&gt; 'articles'],
                'transformer' =&gt; function(Entry $entry) {
                    return [
                        'title' =&gt; $entry-&gt;title,
                        'url' =&gt; $entry-&gt;url,
                        'customProperty' =&gt; $entry-&gt;customProperty,
                    ];
                },
            ];
        },
        'api/entries/&lt;entryId:\d+&gt;.json' =&gt; function($entryId) {
            return [
                'elementType' =&gt; Entry::class,
                'criteria' =&gt; ['id' =&gt; $entryId],
                'one' =&gt; true,
                'transformer' =&gt; function(Entry $entry) {
                    return [
                        'title' =&gt; $entry-&gt;title,
                        'url' =&gt; $entry-&gt;url,
                        'customProperty' =&gt; $entry-&gt;customProperty,
                    ];
                },
            ];
        },
    ]
];
</code></pre>
<p>Accessing <code>https://my-site-url/api/entries/all.json</code> would return a JSON object with an array of all the entries, and accessing <code>https://my-site-url/api/entries/123456.json</code> would return a JSON object with the properties for the Entry with an ID of 123456.</p>

CC BY-SA 4.0
2021-03-05T09:29:27.200Z
2021-03-05T09:29:27.200Z
Martin Spain
<p>You don't need the Element API, or a custom plugin, or GraphQL, or Sprig, for this. Simply set up a template and then call it via ajax. The template can return a chunk of html and use POST or GET parameters to decide what it needs to fetch. If you prefer, the template could just as easily return a chunk of JSON or XML or plain text or whatever else you want. You don't mention if you're using a JS framework, but for simplicity here's a jQuery way using <a href="https://api.jquery.com/load/" rel="nofollow noreferrer">load</a>:</p>
<pre class="lang-html prettyprint-override"><code>/// main template:
    
&lt;button
    type=&quot;button&quot;
    data-url=&quot;/ajax-load-entry?id=123&quot;
    data-element-id=&quot;123&quot;
    class=&quot;js-ajaxLoad&quot;
&gt;
    Load Entry #123
&lt;/button&gt;

&lt;div class=&quot;ajax-result-container-for-123&quot;&gt;&lt;/div&gt;

&lt;script&gt;
    $('.js-ajaxLoad').click(function(){
        var url = $(this).data('url');
        var elementId = $(this).data('elementId');
        $('.ajax-result-container-for-' + elementId).load(url);
    });
&lt;/script&gt;

/// templates/ajax-load-entry.twig template:

{% if craft.app.request.getParam('id') %}
    {% set entry = craft.entries.id(craft.app.request.param('id')).one() %}
    {% if entry %}
        &lt;h1&gt;{{ entry.title }}&lt;/h1&gt;
        {{ entry.body ?? null }}
    {% endif %}
{% endif %}
</code></pre>
<p>I appreciate jQuery's not very fashionable these days, but the same concept could very easily be translated into a native <code>fetch</code> call if you don't need IE11 support (or if you're transpiling). Something like this should work in native JS:</p>
<pre class="lang-html prettyprint-override"><code>&lt;script&gt;
    document.querySelector('.js-ajaxLoad').addEventListener('click', function(){
        let url = this.dataset.url;
        let elementId = this.dataset.elementId;
        fetch(url).then(function(response) {
            return response.text();
        }).then(function (html) {
            document.querySelector('.ajax-result-container-for-' + elementId).innerHTML = html;
        });
    });
&lt;/script&gt;
</code></pre>

CC BY-SA 4.0
2021-03-05T11:26:10.117Z
If I could put both as answers - I would. This is a great example of utilising Craft's own power.
JMKelley
CC BY-SA 4.0
2022-04-28T02:49:19.020Z
Thank you! This works perfectly!
mateostabio
CC BY-SA 4.0
2021-03-05T10:14:13.987Z
2024-01-23T15:03:11.760Z
2024-01-23T15:03:11.760Z
James Smith
<p>I'm simply looking to <code>onClick</code> load an entries content via Ajax. Thought I see a lot of mixed answers here on SO, some referring to Element API, Creating a Plugin and GraphQL. Is there a simple way to just get an entries properties on click e.g. title?</p>

<templating>
Load Entry via Ajax
# Load Entry via Ajax

(Asked by: username_0 on 2021-03-04)

I'm simply looking to `onClick` load an entries content via Ajax. Thought I see a lot of mixed answers here on SO, some referring to Element API, Creating a Plugin and GraphQL. Is there a simple way to just get an entries properties on click e.g. title?

**Tags:** templating


---

## 2 answers

### Answer by username_1 on 2021-03-05. Score: 2 | Accepted answer

I can think of a couple of simple ways to output an entry's properties on a click event. If there aren't too many of them, you could output the properties that you want as data attributes on the link/button element in your Twig template, then access them from a JS click event handler:
{# Twig template #}

    Link text


// JavaScript code
const myLink = document.querySelector('a.myLink');
myLink.addEventListener('click', function() {
    // Get properties
    const title = myLink.getAttribute('data-title');
    const customProperty = myLink.getAttribute('data-custom-property');
});

That's probably the simplest method. If you want to access a lot of properties, you could output them into a JavaScript global variable in your Twig template and access them that way, but that can be messy and pollute the global JS scope.
If you want to get more advanced, the Element API plugin is the next step. This allows you to create endpoints that you can access via XHR/fetch requests, which return JSON data that you specify. See here for an example of how the Element API works.
Using the Element API, your click event handler could fetch the entry's JSON data and output it dynamically as needed. You'd have something like this in your config/element-api.php config file:
 [
        'api/entries/all.json' => function() {
            return [
                'elementType' => Entry::class,
                'criteria' => ['section' => 'articles'],
                'transformer' => function(Entry $entry) {
                    return [
                        'title' => $entry->title,
                        'url' => $entry->url,
                        'customProperty' => $entry->customProperty,
                    ];
                },
            ];
        },
        'api/entries/.json' => function($entryId) {
            return [
                'elementType' => Entry::class,
                'criteria' => ['id' => $entryId],
                'one' => true,
                'transformer' => function(Entry $entry) {
                    return [
                        'title' => $entry->title,
                        'url' => $entry->url,
                        'customProperty' => $entry->customProperty,
                    ];
                },
            ];
        },
    ]
];

Accessing https://my-site-url/api/entries/all.json would return a JSON object with an array of all the entries, and accessing https://my-site-url/api/entries/123456.json would return a JSON object with the properties for the Entry with an ID of 123456.


---

### Answer by username_2 on 2021-03-05. Score: 6

You don't need the Element API, or a custom plugin, or GraphQL, or Sprig, for this. Simply set up a template and then call it via ajax. The template can return a chunk of html and use POST or GET parameters to decide what it needs to fetch. If you prefer, the template could just as easily return a chunk of JSON or XML or plain text or whatever else you want. You don't mention if you're using a JS framework, but for simplicity here's a jQuery way using load:
/// main template:
    

    Load Entry #123






/// templates/ajax-load-entry.twig template:

{% if craft.app.request.getParam('id') %}
    {% set entry = craft.entries.id(craft.app.request.param('id')).one() %}
    {% if entry %}
        {{ entry.title }}
        {{ entry.body ?? null }}
    {% endif %}
{% endif %}

I appreciate jQuery's not very fashionable these days, but the same concept could very easily be translated into a native fetch call if you don't need IE11 support (or if you're transpiling). Something like this should work in native JS:

> **Comments:**
> **username_0**: If I could put both as answers - I would. This is a great example of utilising Craft's own power.  
> **username_3**: Thank you! This works perfectly!  

---

