Client / Server communication

Hello everybody!!!

I`m relatively new to Ghost but I am already totally in love with it!

Now I’m developing my own theme and I faced one serious problem.

I’ll try to explain the plot:
My goal was to make LIVE search through posts on my custom page. LIVE means that there are some <select> elements (or whatever other inputs) and the search executes on ‘change’ event of this inputs.

THE POINT is next: I’ve already made this searching (filtering) page BUT on the client side. I mean API request goes from client and then the search result renders on page only with the help of JS on page. I think that isn’t good at all (it requers many hardcode). And I’ve tried to make the same thing on server side: I’ve made custom async block helper get_posts. It was so useful belause I could use it in my .hbs templates like:

{{#get_posts lang="ru" tag="news" }}
    {{#foreach posts}}
        {{> "post-card"}}
    {{/foreach}}
{{/get_posts}}

That is so READABLE and NICE and NO HARDCODE. And it worked, BUT
the problem i faced is next: i didn`t find any way to dypamically pass filtering options( as lang and tag in the example) that are unputs values on page.

I registered my helper within ghost installation, It means it is executable and accesable only in my .hbs templates. And I can`t execute this template on client JS with

template = Handlebars.compile("template-from-example-here");

because my helper isn’t recognized by Handlebars core. You’ll probably want to say smth like:

Hey, dude, you could use Handlebars.registerHelper('helper_name', (options) => {...})

The point is that this helper is ASYNC and it returns a promise (it makes API request if you didn’t forget). And handlebars threw me errors when I tried register this very async helper.

My questions are: How can I register async helper on client side?
OR
How can Server and Client sides dynamically comunicate?

I tried to insert a script directly inside my page template. Something like this:

<div class ="filtering"> ...filtering options in inputs here... </div>
<div class = "container">
<script type="text/javascript">
    const lang =  document.getElementById('select-lang').value; // the language selected by user
    document.querySelector('.container').innerHTML = `  // tried using interpolation
        {{#get_posts lang="${lang}"}}
               {{#foreach posts}}
                    {{> "post-card"}}
               {{/foreach}}
        {{/get_posts}}
    `;
</script>
</div>

And that didn’t work out. the helper got in its options.hash.lang the ${lang}, but not the lang variable content.
I want you to think how my problem could be solved. I see next solution: somehow registering my helper in Handlebars and using it within Handlebars.compile(); But how could I register an async helper… I didn’t find any information.

Maybe you see totally different solution.

PS: all code in examples is partly pseudo. If you are intreredted in how I made this on client side with JS i could pull my theme on GitHub .

THANKS A LOT!!!

Hey!

The Ghost theme engine is only executed on the serverside, so there is no way within Ghost that you can pass through these options, because they are input in the client, and Ghost serves a static page.

Your original solution is the correct solution - use the content api! You shouldn’t need any hardcoded values other than the content api key, the rest can be read from user inputs (some hard coded defaults would probably be a good idea though)!

1 Like

Thanks a lot for your reply! To be honest I spent a lot of time doing that server stuff and didnt kmow its impossible :smile:
I would like to clarify what i meant under “hardcode” on client side. In my .hbs templates I can use other partials templates like “post-card” that is provided by default in Casper, unlike on client. Imagine: I`ve done Content API request and recieved several json structured information. And if i want to render it on my page i need to build HTML structure of every recieved post. Is there a way to compile a template on client side (like “post-card”)?
I’am searching for that kind of solution because I find this templating stuff awesome. All things are getting much more readable and softcode after it.
Besides, I would like to share my unlimited happiness because of content API. That is really great!

i want to render it on my page i need to build HTML structure of every recieved post. Is there a way to compile a template on client side (like “post-card”)?

Yes! You can use handlebars on the frontend to compile templates - their website has more information: http://handlebarsjs.com/

If you didn’t want to use handlebars you could use template literals which would be a native, but not fully supported way something like this:

const api = new GhostContentApi(options);

function postTemplate(post) {
  return `
    <div>
      <h2> ${post.title} </h2>
      <p> You can put other stuff in here </p>
    </div>
  `;
}

api.posts.browse(yourBrowseOptions)
  .then(posts => posts.map(postTemplate)) // convert post object to html string
  .then(postStrings => postStrings.reduce((a, b) => a + b)) // concat all the strings
  .then(postsHtmlString => {
    // update the DOM
    const container = document.querySelector('.css-selector-for-container');
    container.innerHTML = postsHtmlString;
  });
1 Like