10

I'm new to Node JS. Below is my code. On AJAX call new data is not being rendered. Is this the right way to render data without loading the entire page? Is there any better way to load only data without using AJAX.

App.js file:

   app.get('/users', function(req, res) {

         var query = req.query.search;

         User.find({'name' : new RegExp(query, 'i')}, function(err, users){
         var data = {list:users};
         console.log("Searching for "+data);

         res.render('admin/users',{data:data});
    });

 });

Ajax call in ejs file:

<script>
function showResult(str) {

    var xmlHttp = null;
    xmlHttp = new XMLHttpRequest();
    xmlHttp.open( "GET", "/admin/users?search="+str, true );
    xmlHttp.send( null );
    return xmlHttp.responseText;
}
</script>

<input type="text" id="search" name="search" placeholder="Search" class="form-control col-md-7 col-xs-12" onkeyup="showResult(this.value)" >
Anirudh
  • 2,767
  • 5
  • 69
  • 119

3 Answers3

11

Super simple demo

routes.js

app.get('/search', searchController.index);
app.get('/search_partial', searchController.partial);

searchController.js

const data = [{ text: 'apple' }, { text: 'potato' }, { text: 'sugar' }];

exports.index = (req, res) => {
  res.render('search/index');
};

exports.partial = (req, res) => {
  const query = req.query.search;
  // emulate mongoose query
  const result = data.filter(item => new RegExp(query, 'i').test(item.text));
  res.render('search/partial', { result });
};

search/index.pug

extends ../layout

block content
  .page-header
    h3 Search

  form.form-horizontal(onsubmit="searchPartial(this);return false;")
    .form-group
      label(class='col-sm-2 control-label', for='search') Text
      .col-sm-8
        input.form-control(type='text', name='search', id='search', autofocus=true)
    .form-group
      .col-sm-offset-2.col-sm-8
        button.btn.btn-primary(type='submit')
          i.fa.fa-search
          | Find
  #search-result

search/partial.pug

.row
  each item in result
    .col-sm-3
      h2=item.text

client-side.js

/* eslint-disable */
$(document).ready(function() {

  // Place JavaScript code here...
  function searchPartial(form) {
    var formData = $(form).serializeArray();
    $.get('/search_partial', {
      search: formData[0].value
    }).then(function (data) {
      $('#search-result').html(data);
    });
  }

  window.searchPartial = searchPartial;
});

This sample should help you, as you can see, we need 2 routes

  1. basic route for rendering search index page
  2. the partial view that will be populated with data on server, and then appended to DOM in client javascript

Also recommend you to look at hackaton-starter-kit

Result

enter image description here

Medet Tleukabiluly
  • 11,662
  • 3
  • 34
  • 69
  • Just wondering, would this not cause a security issue? What if someone changes the route to request their own website, wouldn't they be able to run whatever they want? – Alhassan Raad Jan 01 '21 at 18:27
3

Your strategy is correct!

Just need to fix some small things:

  • Routes between server and client should match
  • Ajax API should return data in json format

App.js file

app.get('/admin/users', function(req, res) {

         var query = req.query.search;

         User.find({'name' : new RegExp(query, 'i')}, function(err, users){
         var data = {list:users};
         console.log("Searching for "+data);

         res.json({data:data});
    });

});

Hope that it can help :)

haotang
  • 5,520
  • 35
  • 46
0

To render EJS partials without reloading the page using ajax, check this thread: Render EJS - Node JS

index.js

app.post('/league_fixtures', async function (req, res) {
  try {
    const league_name = req.body.league_name;
    const fixtures = await leagueFixtures(league_name);
    const file = await readFile('./views/fixtures.ejs');
    var fixture_template = ejs.compile(file, { client: true });
    const html = fixture_template({fixtures: fixtures});
    res.send({ html: html });
  } catch (err) {
    res.status(500).send({ error: 'Something failed!' })
  }
});

ajax call

$.ajax({
      url: '/league_fixtures',
      type: 'POST',
      dataType: "json",
      cache: true,
      data: { league_name: league_name },
      success: function(fixtures){
        var html = fixtures['html'];
        $('#panel_' + league_name).html(html);
      },
      error: function(jqXHR, textStatus, err){
        alert('text status '+textStatus+', err '+err)
      }
    })
mahmouds12
  • 31
  • 3
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/30844205) – mswgen Jan 21 '22 at 02:27