Popular combo SELECT2 com milhares de linhas

5 respostas Resolvido
nodejsmysqljavascriptprogramação
F

Fala pessoal, tenho uma aplicação WEB em Node.JS onde ao entrar na rota de cadastro de ocorrências passo ao render da página um array que é uma consulta a uma tabela de cadastro de material que tem mais de 10.000 registros, este array eu uso para popular um combobox SELECT2, está tudo ok, porém meu problema é que como possui muitos registros, a página demora para carregar, o mesmoa contece quando clico no SELECT2, demora para processar, tem alguma forma diferente de eu popular o SELECT2, tipo usando paginação, não sei, por favor, podem me ajudar?

Inicialização do elemento Select2:

<!-- Inicialização do elemento Select2 -->
<script>
    $(function () {
        $('.select2').select2({
            theme: "bootstrap4",
        });
    });
</script>

Consulta:

//Consulta 
async doQuery(queryToDo) {
    let pro = new Promise((resolve, reject) => {
        let query = queryToDo;
        //Executando a consulta
        this.db.query(query, function(err, result) {
            if (err) throw err;
            resolve(result);
        });
    })
    //Retornando o resultado
    return pro.then((val) => {
        return val;
    })
}

//Materiais
async getMateriais() {
    let query = "SELECT * FROM tb_cadastro_material ORDER BY material ASC";
    return this.doQuery(query)
}

Rota que faz a consulta e envia para a página:

let materiais = await DBModel.getMateriais();

//Passa o conteúdo das variáveis para a página principal
res.render('./pageAdmin', {
    //Populando elementos
    DTMaterial: materiais,
    .
    .
    .

E enfim o meu SELECT2 sendo populado no front end:

<option value="">-- Selecione --</option>
<% DTMaterial.forEach((row, index) => { %>
      <option value="<%= row.material %>"><%= row.material %></option>
<% }) %>

Há uma outra forma de popular considerando que a origem dos dados possui milhares de registros, e sim, é necessário todos pois o usuário poderá selecionar qualquer um da lista.

5 Respostas

L

Pelo que vi nesse link: https://select2.org/data-sources/ajax, o select2 tem autocomplete, ou seja, ele vai pesquisando na medida em que for digitando no campo. Talvez vc possa tentar implementar isso em vez de carregar tudo de uma vez.

F

Então @Lucas_Camara, eu tentei de todas as formas usar a documentação deste link que você passou, cara, confesso que não consegui adequar ao meu código, pois eu não recebo os dados de um URL, ai tentei substituir a URL pela variável DTMaterial que contem os dados e também não rolou.

L

Hmmm, na arquitetura do seu sistema, vc não consegue expor algum endpoint REST para retornar uma lista não?


Veja: https://adityasridhar.com/posts/how-to-use-nodejs-without-frameworks-and-external-libraries

Insisto nisso pq vai facilitar muito a sua vida nesse sistema.

F

Vou dar uma olhada e tentar, obrigado

F
Solucao aceita

Consegui…
Segue solução:

Primeiro você deve criar uma API que que traz o resultado de uma query no formato JSON, veja:

1-Cria a rota:

//Rotas para APIs diversas, pode abrir sem login e senha
const { apiMaterial, } = require('../dao/api/apis.js');
rotas.get('/apiMaterial', apiMaterial);

2-Cria o a consulta que será utilizada na rota da API

//Materiais
async getMateriais(pn) {
    let query = "SELECT * FROM tb_cadastro_material WHERE material LIKE '"+ pn +"%' ORDER BY material ASC";
    return this.doQuery(query)
}

3-Cria o arquivo DAO da rota da API:

//NPM Install
const fse = require('fs-extra');

//Importando arquivo site-model.js que possui a classe com as funções de consulta
const DB = require('./../listas/selects');
const FUNCOES = require('./../util/funcoes');
const mysql = require('mysql2');
const config = require('./../../database/config');
const conn = mysql.createPool(config);

module.exports = {
  apiMaterial: (req, res) => {
      let DBModel = new DB(conn);
      (async function () {
          //Variáveis que recebe o mês e(ou) ano escolhido para popular os gráficos
          let filtro_pn = req.query.q;

          //http://jdn001:3000/apiMaterial/?&[q]=92290
          let materiais = await DBModel.getMateriais(filtro_pn);
          return res.json(materiais);

      })();
  },
};

4 - No front-end este é o trecho do componente SELECT2 que é o campo que receberá a lista de itens:

<div class="col-sm-2">
    <div class="form-group">
        <label for="material_ADD" class="label">Material</label>
        <select class="form-control form-control-sm select2"
            style="width: 100%;" name="material_ADD" id="material_ADD"
            required>
        </select>
    </div>
</div>

5-E por fim o script que contém o trecho JQuery com o AJAX consumindo a api e populando o campo SELECT2 (material_ADD):

<script>
    $(document).ready(function () {
        let hostName = $(location).attr('hostname');
        let descricao;
        let custo_unitario;

        $("#material_ADD").select2({
            placeholder: '--Pesquise--',
            minimumInputLength: 3,

            ajax: {
                url: 'http://' + hostName + ':3000/apiMaterial', //Endereço da api
                dataType: 'json',
                type: "GET",
                delay: 250, //Tempo para iniciar a pesquisa durante digitação

                data: function (params) {
                    return {
                        q: params.term, //Valor que será capturado o campo e passado no parâmetro "q" da API (Ex.: http://jdm090:3000/apiMaterial/?&[q]=92290)
                    };
                },

                processResults: function (data) {
                    //Retorna o resultado da pesquisa e popula o select2
                    var res = data.map(function (item) {
                        descricao = item.descricao;
                        custo_unitario = item.valor;

                        return {
                            id: item.material, //value do select2 utilizado no insert/update
                            text: item.material, //texto do select2 utilizado no front-end
                        };
                    });
                    return {
                        results: res
                    };
                },
                cache: true
            },
        //Aqui ao selecionar um item no SELECT2 outros campos são populados baseado no item escolhido
        }).on('change', function () {
            document.getElementById('descricao_ADD').value = descricao;
            document.getElementById('valor_unitario_ADD').value = formatBDToDecimal(custo_unitario);
            document.getElementById('valor_diferenca_ADD').value = formatBDToDecimal((custo_unitario) * document.getElementById('diferenca_ADD').value);
        });
    });
</script>

Nota adicional:
Para popular o SELECT2 com dados já existentes daquele registro, ou seja, ao clicar no botão editar para realizar alterações:

$('#material_EDIT').select2('trigger', 'select', {data: {id: '<%= row.material %>', text: '<%= row.material %>'}});

Solução 100% funcional superando as expectativas

Criado 14 de maio de 2021
Ultima resposta 4 de nov. de 2022
Respostas 5
Participantes 2