Selectize.js with Tags, reload key and value in edit form

Asked

Viewed 785 times

12

I posted the same question in the Gringo OS too.

I’m making a research form (action=GET) where a field uses Selectize.js:

$("#selectize").each(function () {
        $(this).selectize({
            plugins: ['remove_button'],
            valueField: 'AdvogadoId',
            labelField: 'Descricao',
            searchField: ['AdvogadoId', 'Descricao'],
            create: false,
            persist: false,
            preload: true,
            initUrl: "/Advogados/PesquisarJson/",
            initData: true,
            load: function (query, callback) {
                $.ajax({
                    url: "/Advogados/PesquisarJson/",
                    type: 'GET',
                    error: function () {
                        callback();
                    },
                    success: function (res) {
                        callback(res);
                    }
                });
            }
        });
    });

With the empty form, I enter the lawyer’s name and acronym. Everything is filled in correctly. When submitting the research, the values go to the back-end correctly, separated by commas.

When the form is reloaded with the values of the GET, what happens is that each tag appears only with the lawyer’s name filled, without the name. When checking the options, the options chosen appear only as the acronym, and the correct one would be "Acronym - Name".

I tried some solutions like this (does not work, besides being complex for what I need) and this (no use data-data: use only form values).

Is there any way (preferably performative) to load these values correctly on each tag selected on screen?


Code in the Back-end:

    public JsonResult PesquisarJson(String termo = "")
    {
        // Aqui não é EF. É Dapper em cima de Oracle.
        using (var repositorio = new AdvogadoRepositorio())
        {
            var registros = repositorio.Condicao(a => a.DataSaida == null).OrdenarPor(a => a.AdvogadoId).Selecionar();
            return Json(registros.Select(a => new { AdvogadoId = a.AdvogadoId, Descricao = a.AdvogadoId + " - " + a.Nome }).ToList(), 
                JsonRequestBehavior.AllowGet);
        }
    }

HTML:

<div class="selectize-control form-control selectize multi plugin-remove_button">
    <div class="selectize-input items not-full">
        <input type="text" autocomplete="off" tabindex="" style="width: 4px; opacity: 1; position: relative; left: 0px;">
    </div>
    <div class="selectize-dropdown multi form-control selectize plugin-remove_button" style="display: none;">
        <div class="selectize-dropdown-content">
        </div>
    </div>
</div>

Rest result:

[
  {
    "AdvogadoId": "A1",
    "Descricao": "A1 - Fulano de Araujo"
  },
  {
    "AdvogadoId": "A2",
    "Descricao": "A2 - Beltrano de Lima"
  },
  {
    "AdvogadoId": "A3",
    "Descricao": "A3 - Ciclano da Silva"
  },
  {
    "AdvogadoId": "A4",
    "Descricao": "A4 - Herculano Junior"
  },
  ...
]
  • But how do you want to get "Acronym - Name" if the valueField only allows a single attribute? whereas the names of their respective acronyms are in the database and have a ID, the solution would be to take the ID and get the name and acronym of the selected records via backend.

  • You could also customize the selectize source to receive a Fields value array and concatenate the respective ones into the desired format

  • So the challenge is part of the question. I would like these ideas to become an answer.

  • Please edit the question with your controller code, so the answer is not generic

  • @Felipeasunción Feito.

  • @Felipeasuncion I put more information. See if it helps.

Show 1 more comment

2 answers

2

This is because the <input> when selecting is filled with the AdvogadoId and not with Descricao, when you select for example:

selectize.js

What you "see" (gray button with x on the side) is actually the "label" and not the value of <input>, in this case the label uses the Descricao and the input uses the AdvogadoId see valueField: 'AdvogadoId',

The only way "practice" that I see to do as you wish it would be this and put the valueField also as Descricao:

 $("#selectize").each(function () {
    $(this).selectize({
        plugins: ['remove_button'],
        valueField: 'Descricao', //Adicionar descrição aqui também
        labelField: 'Descricao',
        searchField: ['AdvogadoId', 'Descricao'],
        create: false,
        persist: false,
        preload: true,
        initUrl: "/Advogados/PesquisarJson/",
        initData: true,
        load: function (query, callback) {
            $.ajax({
                url: "/Advogados/PesquisarJson/",
                type: 'GET',
                error: function () {
                    callback();
                },
                success: function (res) {
                    callback(res);
                }
            });
        }
    });
});

If you really wanted to send the ids (AdvogadoId) you will have to redo the query using the ids to bring back the descriptions on the next page.

But maybe I can use sessionStorage next to Selectize.js API to keep the options and automatically add them, an example:

$(function() {
    var target = $("#selectize");
    var keySession = "selectizeData2";

    var update = function(a,b) {
        var opts = this.options;
        setTimeout(function() {//Requer timeout
            var values = target.val().split(",");
            console.log(values);

            var list = [];
            for (var k in opts) {
                current = opts[k];
                if (values.indexOf(current.AdvogadoId) !== -1) {
                    list.push({ AdvogadoId: current.AdvogadoId, Descricao: current.Descricao });
                }
            }

            console.log(JSON.stringify(list));
            sessionStorage.setItem(keySession, JSON.stringify(list));
        }, 1);
    };

    var getTarget = function(selectize) {
        var data = sessionStorage.getItem(keySession);
        var parsedData = JSON.parse(data);
            console.log(parsedData);
        if (parsedData) {
            for (var k in parsedData) {
                var current = parsedData[k];
                selectize.addOption([current]);
                selectize.addItem(current.AdvogadoId);
            }
        }
    };

    target.each(function () {
        var handler = $(this).selectize({
            plugins: ['remove_button'],
            valueField: 'AdvogadoId', //Veja que mantive o ID como value
            labelField: 'Descricao',
            searchField: ['AdvogadoId', 'Descricao'],
            create: false,
            persist: false,
            preload: true,
            initUrl: "test.php",
            initData: true,
            "onItemAdd": update, //Adiciona o evento
            "onItemRemove": update, //Adiciona o evento
            load: function (query, callback) {
                $.ajax({
                    url: "test.php",
                    type: 'GET',
                    error: function () {
                        callback();
                    },
                    success: function (res) {
                        callback(res);
                    }
                });
            }
        });

        getTarget(handler[0].selectize);
    });
});

Following the example of @Felipe you can also use a pre-query (although for performance this does not look good when increasing the number of registered clients), would be (it is necessary to clean the input first because if not Selectize.js considers that the ids already exist):

$(function() {
    var target = $("#selectize");
    var currentValue = target.val();

    target.val("");

    target.each(function () {
        $(this).selectize({
            plugins: ['remove_button'],
            valueField: 'AdvogadoId',
            labelField: 'Descricao',
            searchField: ['AdvogadoId', 'Descricao'],
            create: false,
            persist: false,
            preload: true,
            initUrl: "test.php",
            initData: true,
            onInitialize: function() {
                var self = this;
                var value = "," + currentValue + ",";

                $.ajax({
                  url: "test.php",
                  type: 'GET',
                  success: function(res) {
                    res.forEach(function(existingOption) {
                        self.addOption(existingOption);
                        if (value.indexOf("," + existingOption.AdvogadoId + ",") !== -1) {
                            self.addItem(existingOption.AdvogadoId);
                        }
                    });
                  }
                });
            },
            load: function (query, callback) {
                $.ajax({
                    url: "test.php",
                    type: 'GET',
                    error: function () {
                        callback();
                    },
                    success: function (res) {
                        callback(res);
                    }
                });
            }
        });
    });
});
  • It actually works, but I have to address the back-end logic, and that’s not quite what I wanted. I’ll grant the reward but I won’t accept the answer.

1

To solve this problem you will need to make a fix using the method onInitialize the solution is not beautiful, but solves this deficiency of the library:

$(this).selectize({
  plugins: ['remove_button'],
  valueField: 'Sigla',
  labelField: 'Nome',
  searchField: ['Sigla', 'Nome'],
  create: false,
  persist: false,
  preload: true,
  initUrl: "/Advogados/PesquisarJson/",
  initData: true,
  load: function(query, callback) {
    $.ajax({
      url: "/Advogados/PesquisarJson/",
      type: 'GET',
      error: function() {
        callback();
      },
      success: function(res) {
        callback(res);
      }
    });
  },
  // Bugfix
  onInitialize: function() {

    var self = this;
    var value = self.getValue();

    $.ajax({
      url: "/Advogados/PesquisarJson/",
      type: 'GET',
      success: function(res) {

        res.forEach(function(existingOption) {
          self.addOption(existingOption);
          self.addItem(existingOption[self.settings.valueField]);
        });

        self.setValue(value);
        self.blur();
      }
    });

  }
});
  • From what I understand, this code only takes care of how to enter the data in Dropdown, but it does not exchange the options only acronyms for the options "Acronym - Name".

  • It updates the view accordingly :)

  • So, but it didn’t work. That’s what I mean.

  • @Ciganomorrisonmendez the logic of Elipe "works", but it is likely that you would have to change the back-end to support the empty query and so maybe it did not work.

  • @Guilhermenascimento didn’t work here. It would be nice to have a Fiddle to test this.

  • @Ciganomorrisonmendez has reason does not work, I only looked at the logic, lacked the comparative between getValue and the items in foreach

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.