• Guest, before posting your code please take these rules into consideration:
    • It is required to use our BBCode feature to display your code. While within the editor click < / > or >_ and place your code within the BB Code prompt. This helps others with finding a solution by making it easier to read and easier to copy.
    • Don't share a wall of code. All we want is the problem area, the code related to your issue.


    To learn more about how to use our BBCode feature, please click here.

    Thank you, Code Forum.

Node.JS How to filter the list without reloading the page?

dt65231

Coder
How to filter the list without reloading the page?

**Logic**
- the user enters the filter criteria in the filter field;
- result: the list is filtered without reloading the page;

**Note**
The criterion for the filter is the text.
Filtering is carried out by the field: `title`.
In this example, the current content of the `title` field, the text of the type `Articles-...`, is conditional.
In the future, the `title` field may contain a phrase consisting of several words (both a text title and a full name, etc. by analogy).

12.08.2022_17-53-15_Filter.png
12.08.2022_17-55-53.png

12.08.2022_17-57-09.png

**home.controller.js**
JavaScript:
const fs = require('fs');

exports.getHomePage = (req, res) => {
    let query = "SELECT * FROM `articles` ORDER BY id ASC"; // query database to get all the players

    // execute query
    db.query(query, (err, result) => {
        if (err) {
            res.redirect('/');
        }

        res.render('index.ejs', {
            title: "Welcome to DB",
            articles: result
        });
    });
};



**index.routes.js**
JavaScript:
const express = require("express");
const router = express.Router();
const homeController = require('../controllers/home.controller');
router.get('/', homeController.getHomePage);
module.exports = router;


**app.js**
JavaScript:
const express = require('express');
const fileUpload = require('express-fileupload');
const bodyParser = require('body-parser');
const mysql = require('mysql');
const path = require('path');

const app = express();

const articleRoutes = require('./routes/article.routes');
const homeRoutes = require('./routes/index.routes');
const port = 2000;


// create connection to database
// the mysql.createConnection function takes in a configuration object which contains host, user, password and the database name.
const db = mysql.createConnection ({
    host: 'localhost',
    user: 'root',
    password: '',
    database: 'socka'
});

// connect to database
db.connect((err) => {
    if (err) {
        throw err;
    }
    console.log('Connected to database');
});
global.db = db;

// configure middleware
app.set('port', process.env.port || port);                  // set express to use this port
app.set('views', __dirname + '/views');                     // set express to look in this folder to render our view
app.set('view engine', 'ejs');                              // configure template engine
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());                                 // parse form data client
app.use(express.static(path.join(__dirname, 'public')));    // configure express to use public folder
app.use(fileUpload());                                      // configure fileupload

// routes for the app
app.use('/', homeRoutes);
// app.use('/player', playerRoutes);
app.use('/article', articleRoutes);
app.get('*', function(req, res, next){
    res.status(404);

    res.render('404.ejs', {
        title: "Page Not Found",
    });

});

// set the app to listen on the port
app.listen(port, () => {
    console.log(`Server running on port: ${port}`);
});
```

**index.ejs**
HTML:
<!doctype html>
<html lang="ru">
<head>
    <!-- Кодировка веб-страницы -->
    <meta charset="utf-8">
    <!-- Настройка viewport -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>...</title>
   
    <!-- Bootstrap CSS (jsDelivr CDN) -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <!-- Bootstrap Bundle JS (jsDelivr CDN) -->
    <!--
    <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    -->
</head>
<!-- <body> -->
    <body>
        <!-- class="container" -->
        <div class="container">
           
            <!-- div -->
            <div class="border border-success border-3 p-2 vh-100 d-flex flex-column">
                <!-- HEADER  --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- ---->
                <!-- <header class="py-4 text-center text-uppercase fs-4 bg-primary bg-gradient text-white">
                    Header
                    </header> -->
                   
                    <!-- ROW  --- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- --- --- -->
                    <div class="row py-3 flex-grow-1">
                       
                        <!-- LEFT MENU  --- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- -->
                        <div class="col-3 d-flex">
                            <aside class="bg-danger bg-gradient w-100 d-flex justify-content-left align-items-center text-dark fs-5">                              
                                <% if (articles.length > 0) { %>
                                    <ul>
                                        <% articles.forEach((article, index) => { %>
                                        <li>
                                            <input type="hidden" class="articles" name="articles[]" value="<%= article.id %>">    
                                            <span>
                                                <a style="font-weight: bold;" href="#"><%=article.title%></a>
                                            </span>                              
                                            <span>
                                                <a style="font-weight: bold;" href="#"><%=article.owner%></a>
                                            </span>                              
                                            <span>
                                                <a style="font-weight: bold;" href="#"><%=article.number%></a>
                                            </span>                              
                                            <span>
                                                <a style="font-weight: bold;" href="#"><%=article.pos%></a>
                                            </span>
                                           
                                            <!-- <th scope="row"><%= article.id %></th> -->                                                                      
                                            <!-- <td><%= article.title%></td> -->
                                            <!-- <td><%= article.content %></td>
                                            <td><%= article.background %></td> -->
                                            <!-- <td><%= article.owner %></td> -->
                                            <!-- <td>@<%= article.number %></td> -->
                                            <!-- <td>@<%= article.pos %></td>
                                            <td>@<%= article.lang %></td> -->
                                        </li>
                                        <%})%>
                                    </ul>
                                <%}%>
                                </ul>
                            </aside>
                        </div>
                        <!-- PLACEHOLDER  --- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- -->
                        <div class="col-9 d-flex">
                            <main class="bg-light bg-gradient w-100 d-flex justify-content-center align-items-center text-dark fs-5 border border-success border-3">
                            Placeholder
                            </main>
                        </div>
                        <!-- RIGHTBAR  --- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- -->
                        <!-- <div class="col-3 d-flex">
                            <aside class="bg-danger bg-gradient w-100 d-flex justify-content-center align-items-center text-white fs-5">
                            Right Bar
                            </aside>
                        </div> -->
                       
                    </div>
                   
                    <!-- FOOTER -->
                    <!-- <footer class="py-4 bg-info bg-gradient text-center text-uppercase fs-4 text-white">
                    Footer
                    </footer> -->
                   
                </div>
               
            </div> <!-- .container -->
           
        </body>
        </html>

```

**SQL**
SQL:
```
CREATE DATABASE socka;

--
-- Структура таблицы `articles`
--
DROP TABLE IF EXISTS `articles`;
CREATE TABLE IF NOT EXISTS `articles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `content` text,
  `background` text,
  `owner` int(11) DEFAULT NULL,
  `pos` int(11) DEFAULT '0',
  `lang` int(11) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=275 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;


--
-- Структура таблицы `articles`
--
INSERT INTO `articles` (`id`, `title`, `content`, `background`, `owner`, `pos`, `lang`) VALUES
(1, 'Articles-1', 'Content--Articles-1', NULL, NULL, 0, 1),
(2, 'Articles-1-1', 'Content--Articles-1-1', NULL, 1, 0, 1),
(3, 'Articles-1-2', 'Content--Articles-1-2', NULL, 1, 0, 1),
(4, 'Articles-1-3', 'Content--Articles-1-3', NULL, 1, 0, 1),
(5, 'Articles-1-1-1', 'Content--Articles-1-1-1', NULL, 2, 0, 1),
(6, 'Articles-1-1-2', 'Content--Articles-1-1-2', NULL, 2, 0, 1),
(7, 'Articles-1-1-3', 'Content--Articles-1-1-3', NULL, 2, 0, 1),
(8, 'Articles-2', 'Content--Articles-2', NULL, NULL, 0, 1),
(9, 'Articles-3', 'Content--Articles-3', NULL, NULL, 0, 1),
(10, 'Articles-4', 'Content--Articles-4', NULL, NULL, 0, 1),
(11, 'Articles-5', 'Content--Articles-5', NULL, NULL, 0, 2);
 

cbreemer

King Coder
That is curious ! The page I am right now working on does exactly the same thing ! At least conceptually. A list of choices according to a filter field (if it contains data).
I use the oninput trigger of the filter element to re-populate the HTML table with the choices. Just a simple loop through a predefined full list, discarding any entries that do not match the filter. I don't know if this is useful for your example, which is much too elaborate and complicated for me ("too much detail").

.a.jpg
 

dt65231

Coder
That is curious ! The page I am right now working on does exactly the same thing ! At least conceptually. A list of choices according to a filter field (if it contains data).
I use the oninput trigger of the filter element to re-populate the HTML table with the choices. Just a simple loop through a predefined full list, discarding any entries that do not match the filter. I don't know if this is useful for your example, which is much too elaborate and complicated for me ("too much detail").

.View attachment 1563
Could you show me the code?
Or a link to the project?
 

cbreemer

King Coder
Could you show me the code?
Or a link to the project?
I have extracted the relevant code in a page that you can try. All pretty basic stuff.

HTML:
<html>
<head>

<script>

var labels = [ "Lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit" ];
var filter = "";

function addLabels()
{
    for ( var i=0; i<labels.length; i++ )
    {
        var name = labels[i];
        if ( filter != "" && name.toLowerCase().indexOf(filter) < 0 )
        {
            continue;
        }

        const td = document.createElement("td");
        td.appendChild(document.createTextNode(name));

        const tr = document.createElement("tr");
        tr.appendChild(td);
        table.appendChild(tr);
    }
}


function clearTable()
{
    while (table.firstChild)
    {
        table.removeChild(table.firstChild);
    }
}


function setFilter(val)
{
    if ( val == "" )
        document.getElementById("filtertext").value = "";

    filter = val.toLowerCase();

    clearTable();
    addLabels();
}

</script>
</head>

<body onLoad="addLabels()">
<textarea id="filtertext"       rows="1" cols="6" maxlength="6" oninput="setFilter(this.value)"></textarea>
<table    id="table"            ></table>
</body>
</html>
 

cbreemer

King Coder
What amazes me about the test page I just posted is that it works perfectly even though I use the variable table which I neither declared or initialized ‼ Apparently, browsers (both Edge and Chrome) silently interpret table as document.getElementById("table"), which is exactly what I had in the onLoad trigger of my original code . There's not even a message in the console log. If I change the class to something else than table, the code breaks and reports table is not defined, like I would have expected in the first place. Very peculiar... anyone who knows what's up here ?
 

dt65231

Coder
What amazes me about the test page I just posted is that it works perfectly even though I use the variable table which I neither declared or initialized ‼ Apparently, browsers (both Edge and Chrome) silently interpret table as document.getElementById("table"), which is exactly what I had in the onLoad trigger of my original code . There's not even a message in the console log. If I change the class to something else than table, the code breaks and reports table is not defined, like I would have expected in the first place. Very peculiar... anyone who knows what's up here ?
I tried your solution.
It works.
Question:
1.
How do I adapt your solution for my question?
2. How do I transfer the collection to `<script>`?


To try how your solution works in my case, I added the code to \index.ejs.
HTML:
<!-- Begin. My changes -->
<textarea id="filtertext" rows="1" cols="6" maxlength="6" oninput="addLabels()"></textarea>
<button onclick="addLabels()">Filter</button>
<!-- End. My changes -->

and script
HTML:
<script>
        var thisArticles = '<%=articles%>';

        function addLabels() {
            for (var i = 0; i < thisArticles.length; i++) {
                var name = thisArticles[i].title;
                console.log(name);
            }
        }
    </script>



I press the button.
See the result in the picture.
14.08.2022_10-21-00.png


Fragment **\index.ejs**
HTML:
 <!-- End. My Changes  --- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- --- --- -- -->
                    <aside
                        class="bg-danger bg-gradient w-100 d-flex justify-content-left align-items-center text-dark fs-5">

                        <% if (articles.length> 0) { %>
                            <ul>
                                <!-- Begin. My changes -->
                                <textarea id="filtertext" rows="1" cols="6" maxlength="6"
                                    oninput="addLabels()"></textarea>
                                <button onclick="addLabels()">Filter</button>
                                <!-- End. My changes -->

                                <% articles.forEach((article, index)=> { %>
                                    <li>
                                        <input type="hidden" class="articles" name="articles[]"
                                            value="<%= article.id %>">
                                        <span>

                                            <!-- <a style="font-weight: bold;" href="#" onclick="setMessage3('<%=articles[article.id]%>', '<%=article.id%>')"><%=article.title%></a> -->
                                            <a style="font-weight: bold;" href="#"
                                                onclick="setMessage5('<%=article%>')">
                                                <%=article.title%>
                                            </a>
 

Antero360

King Coder
Staff Team
Security Analyst
you can do either one of 2 things...
1) you could save anything the user has entered to state
2) you could make your function asynchronous

option 2 would be preferred if you are not looking to have the page reload

in either way, you would have to prevent the button/input onclick/onchange from creating a postback.
 
Last edited:

dt65231

Coder
you can do either one of 2 things...
1) you could save anything the user has entered to state
2) you could make your function asynchronous

option 2 would be preferred if you are not looking to have the page reload
I'm just studying Node.JS .
I don't really understand what you're talking about..
If it's not hard for you, could you give an example of the code...

Or share links to examples....

Thanks.
 

Antero360

King Coder
Staff Team
Security Analyst
I'm just studying Node.JS .
I don't really understand what you're talking about..
If it's not hard for you, could you give an example of the code...

Or share links to examples....

Thanks.
Sure, no problem.

try something like this:
Code:
<button type="button" onclick="addLabels()" />

js
function addLabels(){
    event.preventDefault();
    //logic to send filtered list
}
 

cbreemer

King Coder
I tried your solution.
It works.
Of course it does 😉 Even if it amazed me at first 🤣
I have since found that, indeed, a variable need not be defined for an element with an id. For example, if you have <table id="foobar">...<table> you can simply refer to foobar for the table element.

Question:
1.
How do I adapt your solution for my question?
2. How do I transfer the collection to `<script>`?
Sorry, I don't really understand what you are asking here...

To try how your solution works in my case, I added the code to \index.ejs.
HTML:
<!-- Begin. My changes -->
<textarea id="filtertext" rows="1" cols="6" maxlength="6" oninput="addLabels()"></textarea>
<button onclick="addLabels()">Filter</button>
<!-- End. My changes -->

and script
HTML:
<script>
        var thisArticles = '<%=articles%>';

        function addLabels() {
            for (var i = 0; i < thisArticles.length; i++) {
                var name = thisArticles[i].title;
                console.log(name);
            }
        }
    </script>



I press the button.
See the result in the picture.
View attachment 1566
It would seem like your array has 175 elements, but not a field with the name title. I am not familiar with EJS though.
 
Top