Select2 4.0.0 valor inicial com Ajax


97

Eu tenho um select2 v4.0.0 sendo preenchido a partir de uma matriz Ajax. Se eu definir o val do select2, posso ver via depuração de javascript que ele selecionou o item correto (# 3 no meu caso), no entanto, isso não é mostrado na caixa de seleção, ainda está mostrando o espaço reservado. insira a descrição da imagem aqui

Considerando que eu deveria estar vendo algo assim: insira a descrição da imagem aqui

Em meus campos de formulário:

<input name="creditor_id" type="hidden" value="3">
<div class="form-group minimal form-gap-after">
    <span class="col-xs-3 control-label minimal">
        <label for="Creditor:">Creditor:</label>
    </span>
    <div class="col-xs-9">
        <div class="input-group col-xs-8 pull-left select2-bootstrap-prepend">
            <select class="creditor_select2 input-xlarge form-control minimal select2 col-xs-8">
                <option></option>
            </select>
        </div>
    </div>
</div>

Meu javascript:

var initial_creditor_id = "3";
$(".creditor_select2").select2({
    ajax: {
       url: "/admin/api/transactions/creditorlist",
       dataType: 'json',
       delay: 250,
       data: function (params) {
           return {
                q: params.term,
                c_id: initial_creditor_id,
                page: params.page
           };
       },
       processResults: function (data, page) {
            return {
                results: data
            };
       },
       cache: true
   },
   placeholder: "Search for a Creditor",
   width: "element",
   theme: "bootstrap",
   allowClear: true
   }).on("select2:select", function (e) {
      var selected = e.params.data;
      if (typeof selected !== "undefined") {
           $("[name='creditor_id']").val(selected.creditor_id);
           $("#allocationsDiv").hide();
           $("[name='amount_cash']").val("");
           $("[name='amount_cheque']").val("");
           $("[name='amount_direct']").val("");
           $("[name='amount_creditcard']").val("");
        }
    }).on("select2:unselecting", function (e) {
        $("form").each(function () {
            this.reset()
        });
        ("#allocationsDiv").hide();
        $("[name='creditor_id']").val("");
    }).val(initial_creditor_id);

Como posso fazer a caixa de seleção mostrar o item selecionado em vez do espaço reservado? Devo enviar isso como parte da resposta JSON AJAX, talvez?

No passado, Select2 exigia uma opção chamada initSelection que era definida sempre que uma fonte de dados personalizada estava sendo usada, permitindo a seleção inicial do componente a ser determinado. Isso funcionou bem para mim na v3.5.


Como é possível? Quando estou tentando ligar selectcom ajaxele levanta o erro, essa opção ajax não é permitida com o select ...
Daggeto

Respostas:


109

Você está fazendo a maioria das coisas corretamente, parece que o único problema que está encontrando é que você não está disparando o changemétodo depois de definir o novo valor. Sem um changeevento, Select2 não pode saber que o valor subjacente mudou, então ele exibirá apenas o espaço reservado. Alterando sua última parte para

.val(initial_creditor_id).trigger('change');

Deve corrigir o seu problema e você deve ver a atualização da IU imediatamente.


Isso pressupõe que você <option>já tenha um que tenha um valuede initial_creditor_id. Se você não selecionar 2 e o navegador, não será capaz de alterar o valor, pois não há opção para alternar, e Selecionar 2 não detectará o novo valor. Percebi que você <select>contém apenas uma opção, a do espaço reservado, o que significa que você precisará criar a nova <option>manualmente.

var $option = $("<option selected></option>").val(initial_creditor_id).text("Whatever Select2 should display");

E, em seguida, anexe-o ao <select>que você inicializou em Select2. Você pode precisar obter o texto de uma fonte externa, que é onde initSelectioncostumava entrar em jogo, o que ainda é possível com o Select2 4.0.0. Como uma seleção padrão, isso significa que você terá que fazer a solicitação AJAX para recuperar o valor e, em seguida, definir o <option>texto imediatamente para se ajustar.

var $select = $('.creditor_select2');

$select.select2(/* ... */); // initialize Select2 and any events

var $option = $('<option selected>Loading...</option>').val(initial_creditor_id);

$select.append($option).trigger('change'); // append the option and update Select2

$.ajax({ // make the request for the selected data object
  type: 'GET',
  url: '/api/for/single/creditor/' + initial_creditor_id,
  dataType: 'json'
}).then(function (data) {
  // Here we should have the data object
  $option.text(data.text).val(data.id); // update the text that is displayed (and maybe even the value)
  $option.removeData(); // remove any caching data that might be associated
  $select.trigger('change'); // notify JavaScript components of possible changes
});

Embora possa parecer muito código, é exatamente assim que você faria para caixas de seleção não Select2 para garantir que todas as alterações foram feitas.


14
Alguma ideia de como pré-selecionar várias opções para caixas de seleção múltipla?
user396404

6
@ user396404 os mesmos conceitos devem ser aplicados, apenas passe uma lista de ids em val()vez de um único id. Ou apenas acrescente vários <option selected>e isso deve ser tratado automaticamente.
Kevin Brown

5
Sei que esta resposta tem mais de um ano, mas a documentação do Select2 para a pergunta do FAQ: "Como posso definir as opções selecionadas inicialmente ao usar AJAX?" ainda aponta para isso. Anexei um JSFiddle como um exemplo funcional para v4.0.3 jsfiddle.net/57co6c95
Clint

2
Há um problema. E se eu quiser solicitar mais do que apenas id e texto? Eu tentei, mas a opção de dados apenas obtém os dados para templateResult e ignora-os para templateSelection. Qualquer ideia?
ClearBoth

2
Além disso, tentei essa solução, mas infelizmente depois de chamar $select.trigger('change');a opção ainda está com o texto Carregando ... , embora data.texttivesse exatamente o texto que queria. Talvez isso não seja mais compatível com o 4.0.6 .
Alisson

28

O que fiz é mais limpo e precisa fazer duas matrizes:

  • um contém uma lista de Object com id e um texto (no meu caso, seu id e nome, dependendo do seu templateResult) (é o que você obtém da consulta ajax)
  • o segundo é apenas uma matriz de ids (valor de seleção)

Eu inicializo select2 usando o primeiro array como dados e o segundo como val.

Uma função de exemplo com como parâmetros um dicionário id: nome.

function initMyList(values) {
    var selected = [];
    var initials = [];

    for (var s in values) {
        initials.push({id: s, name: values[s].name});
        selected.push(s);
    }

    $('#myselect2').select2({
        data: initials,
        ajax: {
            url: "/path/to/value/",
            dataType: 'json',
            delay: 250,
            data: function (params) {
                return {
                    term: params.term,
                    page: params.page || 1,
                };
            },
            processResults: function (data, params) {
                params.page = params.page || 1;

                return {
                    results: data.items,
                    pagination: {
                        more: (params.page * 30) < data.total_count
                    }
                };
            },
            cache: true
        },
        minimumInputLength: 1,
        tokenSeparators: [",", " "],
        placeholder: "Select none, one or many values",
        templateResult: function (item) { return item.name; },
        templateSelection: function (item) { return item.name; },
        matcher: function(term, text) { return text.name.toUpperCase().indexOf(term.toUpperCase()) != -1; },
    });

    $('#myselect2').val(selected).trigger('change');
}

Você pode alimentar o valor inicial usando chamadas ajax e usar jquery promessas para fazer a inicialização select2.


3
Esta é definitivamente a melhor maneira de fazer isso. Manipular o DOM adicionando <option>não parece ser a maneira mais lógica de fazer isso. É assim que eu faço no 4.0
jiaweizhang

2
@ firebird631, sua solução é brilhante, funciona e muito obrigado!
userlond

esta é a solução mais limpa que vi até agora
Jimmy Ilenloa

Vou observar que internamente a dataopção é apenas gerar <option>tags e adicioná-las ao select. Essa resposta não cobre como você lida com casos em que precisa acessar uma API para obter mais informações, mas acho que esse é um caso menos comum.
Kevin Brown

Olá com ajax não estou conseguindo fazer isso. Quando envio uma lista com dois objetos não há problema, ele tenta inserir aqueles dois objetos mas apenas um inserido. e já selecionado automaticamente. Nunca consegui ver duas opções, até enviei dois itens.
Sahin Yanlık

7

Funciona para mim ...

Não use jQuery, apenas HTML: Crie o valor da opção que você exibirá como selecionado . Se o ID estiver nos dados select2, ele será selecionado automaticamente.

<select id="select2" name="mySelect2">
  <option value="mySelectedValue">
        Hello, I'm here!
  </option>
</select>

Select2.org - Valores pré-selecionados padrão


6

A questão de ser forçado a trigger('change')me deixar maluco, já que eu tinha um código customizado na changetrigger, que só deveria acionar quando o usuário mudar a opção no menu suspenso. IMO, a mudança não deve ser acionada ao definir um valor de inicialização no início.

Eu cavei fundo e encontrei o seguinte: https://github.com/select2/select2/issues/3620

Exemplo:

$dropDown.val(1).trigger('change.select2');


4

Um cenário que eu não vi as pessoas realmente responderem é como ter uma pré-seleção quando as opções são originadas de AJAX e você pode selecionar várias. Como esta é a página de acesso para a pré-seleção de AJAX, adicionarei minha solução aqui.

$('#mySelect').select2({
    ajax: {
        url: endpoint,
        dataType: 'json',
        data: [
            { // Each of these gets processed by fnRenderResults.
                id: usersId,
                text: usersFullName,
                full_name: usersFullName,
                email: usersEmail,
                image_url: usersImageUrl,
                selected: true // Causes the selection to actually get selected.
            }
        ],
        processResults: function(data) {

            return {
                results: data.users,
                pagination: {
                    more: data.next !== null
                }
            };

        }
    },
    templateResult: fnRenderResults,
    templateSelection: fnRenderSelection, // Renders the result with my own style
    selectOnClose: true
}); 

3

Se você estiver usando um templateSelection e ajax, algumas dessas outras respostas podem não funcionar. Parece que criar um novo optionelemento e definir o valuee textnão satisfará o método de modelo quando seus objetos de dados usarem outros valores além de id e texto.

Aqui está o que funcionou para mim:

$("#selectElem").select2({
  ajax: { ... },
  data: [YOUR_DEFAULT_OBJECT],
  templateSelection: yourCustomTemplate
} 

Confira o jsFiddle aqui: https://jsfiddle.net/shanabus/f8h1xnv4

No meu caso, tive que processResultsentrar, pois meus dados não continham os campos obrigatórios ide text. Se precisar fazer isso, você também precisará executar sua seleção inicial por meio da mesma função. Igual a:

$(".js-select2").select2({
  ajax: {
    url: SOME_URL,
    processResults: processData
  },
  data: processData([YOUR_INIT_OBJECT]).results,
  minimumInputLength: 1,
  templateSelection: myCustomTemplate
});

function processData(data) {
  var mapdata = $.map(data, function (obj) {      
    obj.id = obj.Id;
    obj.text = '[' + obj.Code + '] ' + obj.Description;
    return obj;
  });
  return { results: mapdata }; 
}

function myCustomTemplate(item) {
     return '<strong>' + item.Code + '</strong> - ' + item.Description;
}

FINALMENTE!!!!! Nossa, isso não poderia ter sido mais frustrante !! Eu estava usando "nome" em vez de "texto" e isso estava me matando. Mudei para a tecla padrão de "texto" e está funcionando perfeitamente agora. Obrigado!
HTMLGuy

1

depois de passar algumas horas procurando uma solução, decidi criar a minha própria. Ele é:

 function CustomInitSelect2(element, options) {
            if (options.url) {
                $.ajax({
                    type: 'GET',
                    url: options.url,
                    dataType: 'json'
                }).then(function (data) {
                    element.select2({
                        data: data
                    });
                    if (options.initialValue) {
                        element.val(options.initialValue).trigger('change');
                    }
                });
            }
        }

E você pode inicializar as seleções usando esta função:

$('.select2').each(function (index, element) {
            var item = $(element);
            if (item.data('url')) {
                CustomInitSelect2(item, {
                    url: item.data('url'),
                    initialValue: item.data('value')
                });
            }
            else {
                item.select2();
            }
        });

E, claro, aqui está o html:

<select class="form-control select2" id="test1" data-url="mysite/load" data-value="123"></select>

Ótima ideia para um procedimento de inicialização genérico.
Carlos Mora,

1

Para uma solução simples e semântica prefiro definir o valor inicial em HTML, exemplo:

<select name="myfield" data-placeholder="Select an option">
    <option value="initial-value" selected>Initial text</option>
</select>

Portanto, quando eu chamo, $('select').select2({ ajax: {...}});o valor inicial é initial-valuee seu texto de opção é Initial text.

Minha versão atual do Select2 é 4.0.3 , mas acho que tem uma grande compatibilidade com outras versões.


Acho que você está salvando não apenas um valor selecionado, mas também um texto em seu banco de dados, para que possa recuperá-lo assim ... caramba!
ITDesigns.eu

@ ITDesigns.eu, acho que não, o valor sento to database é initial-valuee o texto Initial textatua como um placeholder, não é enviado para o banco de dados. Ele está funcionando em meu aplicativo.
Marcio Mazzucato

por que eu precisaria de um espaço reservado em vez de um texto real na opção real ?!
ITDesigns.eu

@ ITDesigns.eu, Select2 pega essa informação e se monta
Marcio Mazzucato

1

https://github.com/select2/select2/issues/4272 apenas isso resolveu meu problema. mesmo que você defina o valor padrão por opção, você tem que formatar o objeto, que tem o atributo text e é isso que você deseja mostrar na sua opção. então, sua função de formato tem que usar ||para escolher o atributo que não está vazio.


0

Estou adicionando esta resposta principalmente porque não posso comentar acima! Achei que foi o comentário de @Nicki e seu jsfiddle, https://jsfiddle.net/57co6c95/ , que acabou fazendo com que isso funcionasse para mim.

Entre outras coisas, deu exemplos do formato para o json necessário. A única alteração que tive que fazer foi que meus resultados iniciais foram retornados no mesmo formato que a outra chamada de ajax, então tive que usar

$option.text(data[0].text).val(data[0].id);

ao invés de

$option.text(data.text).val(data.id);

0

Crie uma combinação de ajax simples com o valor inicial selecionado para select2 4.0.3

<select name="mycombo" id="mycombo""></select>                   
<script>
document.addEventListener("DOMContentLoaded", function (event) {
    selectMaker.create('table', 'idname', '1', $("#mycombo"), 2, 'type');                                
});
</script>  

biblioteca .js

var selectMaker = {
create: function (table, fieldname, initialSelected, input, minimumInputLength = 3, type ='',placeholder = 'Select a element') {
    if (input.data('select2')) {
        input.select2("destroy");
    }
    input.select2({
        placeholder: placeholder,
        width: '100%',
        minimumInputLength: minimumInputLength,
        containerCssClass: type,
        dropdownCssClass: type,
        ajax: {
            url: 'ajaxValues.php?getQuery=true&table=' + table + '&fieldname=' + fieldname + '&type=' + type,
            type: 'post',
            dataType: 'json',
            contentType: "application/json",
            delay: 250,
            data: function (params) {
                return {
                    term: params.term, // search term
                    page: params.page
                };
            },
            processResults: function (data) {
                return {
                    results: $.map(data.items, function (item) {
                        return {
                            text: item.name,
                            id: item.id
                        }
                    })
                };
            }
        }
    });
    if (initialSelected>0) {
        var $option = $('<option selected>Cargando...</option>').val(0);
        input.append($option).trigger('change'); // append the option and update Select2
        $.ajax({// make the request for the selected data object
            type: 'GET',
            url: 'ajaxValues.php?getQuery=true&table=' + table + '&fieldname=' + fieldname + '&type=' + type + '&initialSelected=' + initialSelected,
            dataType: 'json'
        }).then(function (data) {
            // Here we should have the data object
            $option.text(data.items[0].name).val(data.items[0].id); // update the text that is displayed (and maybe even the value)
            $option.removeData(); // remove any caching data that might be associated
            input.trigger('change'); // notify JavaScript components of possible changes
        });
    }
}
};

e o lado do servidor php

<?php
if (isset($_GET['getQuery']) && isset($_GET['table']) && isset($_GET['fieldname'])) {
//parametros carga de petición
parse_str(file_get_contents("php://input"), $data);
$data = (object) $data;
if (isset($data->term)) {
    $term = pSQL($data->term);
}else{
    $term = '';
}
if (isset($_GET['initialSelected'])){
    $id =pSQL($_GET['initialSelected']);
}else{
    $id = '';
}
if ($_GET['table'] == 'mytable' && $_GET['fieldname'] == 'mycolname' && $_GET['type'] == 'mytype') {

    if (empty($id)){
        $where = "and name like '%" . $term . "%'";
    }else{
         $where = "and id= ".$id;
    }

    $rows = yourarrayfunctionfromsql("SELECT id, name 
                    FROM yourtable
                    WHERE 1 " . $where . "
                    ORDER BY name ");
}

$items = array("items" => $rows);
$var = json_encode($items);
echo $var;
?>

-4

Oi estava quase encerrando isso e volte para selecionar 3.5.1. Mas finalmente consegui a resposta!

$('#test').select2({
    placeholder: "Select a Country",
    minimumResultsForSearch: 2,
    ajax: {
        url: '...',
        dataType: 'json',
        cache: false,
        data: function (params) {
                var queryParameters = {
                    q: params.term
                }
                return queryParameters;
        },
        processResults: function (data) {
            return {
                results: data.items
            };
        }
    }
});

var option1 = new Option("new",true, true);

$('#status').append(option1);

$('#status').trigger('change');

Apenas certifique-se de que a nova opção seja uma das opções select2. Eu recebo isso por um json.


Olá - o que é '#status'? deve ser '#test'?
user2808054
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.