2009-03-30 4 views
14

Ho due < selezionare> caselle in un modulo. Selezionando una voce nel primo < seleziona> la casella determinerà cosa dovrebbe apparire nel secondo < seleziona> (usando Ajax http_request).Modo più rapido per popolare <select> con Javascript

In alcuni casi, nella seconda selezione ci possono essere ben 500 voci (ipotesi) e l'aggiornamento in IE richiede 5-10 secondi. Firefox sembra funzionare perfettamente.

Mi chiedo se c'è un modo più veloce per raggiungere questo obiettivo. Attualmente il server crea una stringa che lo passa al client, che viene quindi scomposto e aggiunge ciascun elemento alla selezione creando un elemento opzione e quindi aggiungendolo allo < seleziona>.

ho provato per creare l'intero oggetto di selezione come una stringa sul server e aggiungere che alla forma, ma per qualche motivo che non avrebbe funzionato in Firefox (perso qualcosa?)

Grazie

risposta

2

Impostarlo usando SelectElement.innerHTML sarebbe il più veloce ... ma that FAILS in IE.

ultima volta che ho controllato, si può fare questo in IE, se si avvolge tutte le opzioni in un falso <div> tag, o impostare l'intera .outerHTML della lista di selezione in IE.

0

Sarebbe di grande aiuto vedere il tuo codice.

Se si crea un elemento <option>e aggiungendolo ogni iterazione, è consigliabile creare tutti gli elementi <option> in una volta, e poi li aggiungendo contemporaneamente.

Così (in psuedocodarlo):

// Don't do this: 
for choice in choices: 
    option = new Options(choice) 
    select.append(option) 


// Do this instead 
var options = array() 

for choice in choices: 
    options.append(new Options(choice)) 

for option in options: 
    select.append(option) 

// Or you might try building the select element off-screen and then appending to the DOM 
var options = array() 
var select = new SelectElement() 

for choice in choices: 
    select.append(new Options(choice)) 

dom_element.append(select) 
+0

come fa con l'aiuto array? devi ancora chiamare {n} appende all'elenco di selezione (che è ciò che causa il problema di velocità, dal momento che il browser deve determinare dopo ogni aggiunta se la dimensione dell'elenco deve essere aggiornata) – scunliffe

+0

@scunliffe - l'ottimizzazione del browser raramente arriva fino all'analisi di complessità Big-O. La mia ipotesi è che IE potrebbe ritardare il rendering dei nuovi elementi Option sullo schermo se fossero tutti collegati al DOM in una volta, il che dovrebbe accelerare le cose. Solo qualcosa da provare. – Triptych

1

Vorrei creare l'intero selezionare sul server e iniettarla nella pagina. Questo approccio ignora le fastidiose discrepanze del browser e riduce la complessità del codice lato client.

Hai detto che l'hai provato, ma non è riuscito a Firefox. Suggerirei perseverante nel farlo funzionare, postando un'altra domanda per chiedere aiuto su quel problema, o modificando la tua domanda per mostrarci cosa hai fatto che non ha funzionato in Firefox.

19

500 elementi non è molto, anche per IE. Devi fare qualcos'altro per causare il ritardo.

Ho appena provato con oltre 500 opzioni in IE6, IE7, FF2 e FF3 e tutti erano quasi istantanei. Ho usato questo codice:

var data = [ 
    { text: 'foo', value: 'bar' }, 
    // ... 
    { text: 'foo', value: 'bar' } 
]; 

var select = document.getElementsByTagName('select')[0]; 
select.options.length = 0; // clear out existing items 
for(var i=0; i < data.length; i++) { 
    var d = data[i]; 
    select.options.add(new Option(d.text, i)) 
} 

Suggerirei di profilare il bit di codice che sta recuperando i dati e popolando il menu a discesa. Qualcos'altro potrebbe occupare il tempo. Ad esempio, verifica che il codice "interrompa" il valore di stringa restituito dal server sia nitido (sembra che tu stia eseguendo l'analisi personalizzata in quel punto).

+5

Um ... non dovrebbe essere 'select.options.add (new Option (d.text, d.value))'? – tzot

0

Quando uso la prima versione di questo funziona, ma può essere molto lento nell'aggiornare la seconda selezionare

 
<html> 
<form id='myform' method='post' action='$_SERVER[PHP_SELF]'> 
<table> 
<tr><td><select onselect='CALL_AJAX_AND_UPDATE();'></select></td></tr> 
<tr><td><select id='selectid'></select></td></tr> 
</table> 
</form> 
</html> 

<script type=\"text/javascript\"> 
function UPDATE(updatedata) 
{     
    var itemid = document.getElementById('selectid');    

    var data = updatedata.split('|'); 
    var len = data.length;               

    for(i=0; i < len; i ++) 
    { 
     var opt = document.createElement('option'); 
     opt.text = data[i]; 

     try 
     { 
      itemid.add(opt, null);       
     } 
     catch(ex) 
     { 
      itemid.add(opt);  
     }  
    }           
} 
</script> 

Questa versione funziona in IE, ma Firefox non sembra inviare i secondi dati seleziona. Ho perso qualcosa con questo.

 
<html> 
<form id='myform' method='post' action='$_SERVER[PHP_SELF]'> 
<table> 
<tr><td><select onselect='CALL_AJAX_AND_UPDATE();'></select></td></tr> 
<tr><td><div id='addselect'></div></td></tr> 
</table> 
</form> 
</html> 

<script type=\"text/javascript\"> 
function UPDATE(updatedata) 
{    
    // update data is full select html 
    var itemid = document.getElementById('addselect');    
    itemid.innerHTML = updatedata;               
} 
</script> 
2

Il problema di tutte queste risposte con SelectElement.innerHTML è che non si può fare questo trucco con SELECT. La soluzione è usare innerHTML sul PARENT dell'elemento SELECT stesso. Quindi nel codice ajax/jquery/qualsiasi codice creare una stringa che contiene TUTTO l'HTML SELECT, e quindi ottenere il titolare (un div o span o qualsiasi altra cosa) e impostare il innerHTML sulla stringa che hai costruito.

Sarà necessario isolare SELECT dalla pagina e assegnargli un elemento genitore esplicito (span o div) per impedire che altri elementi html vengano danneggiati quando si distrugge/ricostruisce l'elemento SELECT.

Risposta breve:

parentselectelement.removeChild(selectelement); 
parentselectelement.innerHTML = "<select ...><options...></select>"; 
1

Non dimenticare di aggiungere al document.createDocumentFragment() prima, prima di aggiungere che al SELECT.

4

Il primo codice è bene, ma questo funziona meglio per me:

var data = [ 
    { text: 'uno', value: '1' }, 
    {text: 'dos', value: '2' } 
]; 

var select = document.getElementById('select-choice-1'); 
select.options.length = 0; // clear out existing items 
for (var i = 0; i < data.length; i++) { 
    var d = data[i]; 
    select.options.add(new Option(d.text, d.value)) 
} 
0

Mi piace risposte di Crescent freschi e Kemal fadillah del dato che sia l'uso:

select.options.add(new Options(name, value)) 

Per quanto riguarda l'oggetto di dati vi consiglio un piccolo tweak come segue:

var data = { 
    'uno': 1, 
    'dos': 2 
}; 

var select = document.getElementById('select-choice-1'); 
select.options.length = 0; // clear out existing items 
for (var i in data) { 
     select.options.add(new Option(i, data[i])); 
} 
0

Se non ti dispiace usare CoffeeScript, quindi il seguente cod e riempie un elenco di selezione con dati JSON in un paio di righe.

HTML

<select id="clients"></select> 

CoffeeScript

fillList=($list, url)=> 
    $.getJSON(url) 
    .success((data)-> 
     $list 
     .empty() 
     .append("<option value=\"#{item.Id}\">#{item.Name}</option>" for item in data) 
    ) 

$ -> 
    fillList($('#clients'), '/clients/all') 

Nota: Il loop all'interno del append genera l'intera stringa HTML prima di chiamare il metodo di appendvolta. Questo è bello ed efficiente.

Esempio JSON

[ 
    {"Id":"1","Name":"Client-1"}, 
    {"Id":"2","Name":"Client-2"} 
]