4

It's one of the first time that I use express.js and Handlebars. I need to autocomplete this field: <input type="text" id="myInput" autocomplete="on" placeholder="Search here...">. When everyone digit to this text, I need to make a POST and after a GET without refreshing the content in the page. The problem is, when I do the GET, Handlebars refresh all page. This is the command that I use:

res.render('home',{ items:typeOfCategory}); 

and this is the structure of the hbs:

{{#if items}}
<ul>
{{#each items}} 
<li>{{this.title}}</li>   

{{/each}}
</ul>
{{/if}}

My question is: how to avoid the refreshing of the all page? Thanks

TGrif
  • 5,725
  • 9
  • 31
  • 52
nani
  • 382
  • 5
  • 15

2 Answers2

4

I had read something like that in another question. Based on this tutorial: I found the answer to all my problems. this tutorial explain how to use a PJAX library that manages both the client and server side. Thanks to 3 rows of code you can obtain a speed navigation without reload the page.

  1. Install client side library from jQuery-pjax page
  2. into your html page that send the request add: <a href='/yourLink' data-pjax='main'>YourLink</a>

where main is the div that will content yout change. In my case is:

 <div id="main" class="main">                    
       {{{body}}}                    
 </div>
  1. In your.js file add $('a[data-pjax]').pjax(); This command 'simply call the pjax extension on every element that contains the data attribute ‘data-pjax’'

  2. Install inside express the depency with the command: npm install --save express-pjax

  3. Set your server:

    var app = express();
    var pjax = require('express-pjax');
    
    ...
    
    app.use(pjax())
    

  1. Replace the normal rendering:

res.render('index', {title: "Index"});

with

res.renderPjax('index', {title: "Index"});

UPDATE Alternatively you can obtain the same result. Consider that the structure of the project is as follows:

views
  |-> partials
  |      |-> addtest.hbs
  |
  |-> index.hbs

For example, image that in your index.hbs you have a sidebar with different items, described in this way:

<li>
    <a href="#testDB" data-toggle="collapse" aria-expanded="false" class="dropdown-toggle">
   <img src="../img/database-data.svg" class="svg icon">Test</a>
    <ul class="collapse list-unstyled select-specific" id="testDB">
        <li value="addTest" class=" ">
            <a href="#" id="add-new-test">Add Test</a>
        </li>
         ....
         ....
    </ul>
 </li>

Inside the partials directory you have a simply form. Now for manage the form you have to do two operations:

  1. Server side: For switching from one partial to another without refresh the page, you specify:

    router.get('/addtest', function (req, res) { res.status(200); res.header("Content-Type", "text/html"); res.render('partials/addtest', {title: "Add Test"}); });

  2. Client side: In your client side file, you add make a simple get request:

    $('#add-new-test').click(function (event) { $.get('/addtest').then(function (data) { $('#main').html(data); }); });

In this way, when you make a get request with the same address (i.e in this case /addtest) the client add a part of code inside your view without refresh all.

NOTE: Keep in mind that, if you needed a some file.js in your partial, for load the file, use this:

<script>
var url = "/scripts/script.js";
$.getScript(url);
</script>

This is used for avoid: “Synchronous XMLHttpRequest on the main thread is deprecated…” because the call is asynchronous. For more info..

faienz93
  • 161
  • 2
  • 18
  • Antonio, you champion! I did another way vanilla js with fetch. Client side script inside the onclick async function: let connection = await fetch(`invoice/addcart/${productCodeNumber}`); let response = await connection.text(); const invoice = document.getElementById('invoice'); invoice.innerHTML = response; So pretty much use fetch on client side to go to your route and get the html as response text and then put it into the ID.innerHTML. On server side, I used the partial file and loaded it without layout. Same as Antonio but the res.render part is layout: false flag. – Nhon Ha Sep 02 '20 at 02:10
0

The problem here is that you're making the browser request a new resource each time. This is triggering your templating and serving up a brand new page every time.

You'll want to make an express endpoint which returns JSON, and then send up a request to that endpoint using something like AJAX (found in jQuery) or a similar library. This way you can make a call up to your web server, express can return you some data in a JSON format (res.json({}) and your frontend can then interpret that response and decide how to display it on the DOM.

This sort of partial updating is where you start to need frontend JS along side programatic endpoints that return JSON. This is often where some of these big frontend frameworks like Vuejs and Angular thrive, but if you're new to this sort of thing I'd recommend using jQuery to make a HTTP call to your server and return the JSON down to the frontend.

Elliot Blackburn
  • 3,759
  • 1
  • 23
  • 42
  • the request of this task is that the http must be done in express, so I could use express and ajax? – nani Dec 12 '17 at 12:29
  • @nani Your express controller, the function that accepts `req`, `res`, (etc) does not have to call res.render, that is simply one way to return a response. You will use `res.json(object)` where `object` is the data you wish to pass back. It will send this over HTTP back to the AJAX function. This can then be used on the frontend. So yes, you can and should continue to use Express for the API side. See the docs - http://expressjs.com/en/4x/api.html#res.json – Elliot Blackburn Dec 12 '17 at 16:22