2013-02-02 27 views
9

Próbuję scalić dwie tablice obiektów, aby zweryfikować formularz. Zwykła metoda concat nie wydaje się działać w takich okolicznościach. Concat działa ze zwykłymi tablicami numerycznymi i łańcuchowymi, ale nie z tablicami obiektów. Linia var allTags = allInputs.concat(allSelects); nie działa.Scalanie dwóch macierzy obiektów (NodeList) w JavaScript

var allInputs = document.getElementsByTagName("input"); 
alert("Inputs: " + allInputs.length); 

var allSelects = document.getElementsByTagName("select"); 
alert("Selects: " + allSelects.length); 

var allTags = allInputs.concat(allSelects); 
alert("allTags: " + allTags.length); 
+1

nie jest tablica jego tablicą jak przedmiotu (NodeList) – salexch

+0

Jest to w rzeczywistości NodeList, a więc nie ma sposobu concat. – THEtheChad

Odpowiedz

19

Concat współpracuje ze zwykłych tablic numerycznych i łańcuchowych, ale nie robi z tablicami obiektów.

Właściwie to robi, ale NodeList przypadki nie mają metodę concat i Array#concat nie posiada środki identyfikacji, które chcesz spłaszczyć tych (bo nie jesteś tablic).

Ale nadal jest dość łatwo zrobić (zobacz poniżej zastrzeżenie). Zmień tę linię:

var allTags = allInputs.concat(allSelects); 

do

var allTags = []; 
allTags.push.apply(allTags, allInputs); 
allTags.push.apply(allTags, allSelects); 

Live Example | Source

To działa przy użyciu trochę trick: Array#push akceptuje zmienną liczbę elementów, aby dodać do tablicy, a Function#apply wywołuje funkcję korzystając z daną wartość dla this (w naszym przypadku allTags) oraz wszelkie array- jak obiekt jako argumenty do przekazania. Ponieważ instancje NodeList są podobne do tablic, push z przyjemnością przenosi wszystkie elementy listy do tablicy.

Takie zachowanie Function#apply (nie wymaga drugiego argumentu naprawdę tablicy) jest bardzo jasno określone w opisie, jest dobrze obsługiwane przeglądarkami.

Niestety, IE6 i 7 nie obsługują powyżej (myślę, że to konkretnie za pomocą gospodarz obiektów   — NodeLists   — dla Function#apply jest drugi argument), ale potem, nie powinno być wspieranie im, albo . :-) IE8 też nie jest bardziej problematyczne. IE9 jest z tego zadowolony.

Jeśli trzeba wspierać IE8 i wcześniej, niestety, myślę, że utkniesz z nudnej starej pętli:

var allInputs = document.getElementsByTagName('input'); 
var allSelects = document.getElementsByTagName('select'); 
var allTags = []; 

appendAll(allTags, allInputs); 
appendAll(allTags, allSelects); 

function appendAll(dest, src) { 
    var n; 

    for (n = 0; n < src.length; ++n) { 
    dest.push(src[n]); 
    } 

    return dest; 
} 

Live Example | Source

To ma działa na IE8 i wcześniejszych (i innych).

+0

Wielkie dzięki za pomoc. Jestem początkujący. – user2035797

+0

@ user2035797: Bez obaw, dodałem także przykład działający na IE8 i wcześniejszych. –

+0

+1 wow, dzięki za wszystkie informacje o obsłudze przeglądarki! – Christophe

0

Wygląda na underscore.js w ogóle? Można zrobić

var allSelectsAndInputs = _.union(_.values(document.getElementsByTagName("input")),_.values(document.getElementsByTagName("select"))); 

Aby uzyskać więcej informacji, patrz: http://underscorejs.org/#extend

Funkcja ta jest przeznaczona dla obiektów, ale działa w tym ustawieniu.

+0

faktycznie, gram z tym ... wydaje się nieco off. czekaj. –

+2

Nie sugeruj używania takiej biblioteki do jednorazowej potrzeby ... – MaxArt

+0

Sprawdzę podkreślenie dzięki – user2035797

2

document.get[something] zwraca NodeList, który wygląda bardzo podobnie do Array, ale ma wiele charakterystycznych cech, z których dwa są:

  • Nie zawiera metodę concat
  • Wykaz pozycji jest live. Oznacza to, że zmieniają się, gdy dokument zmienia się w czasie rzeczywistym.

Jeśli nie ma żadnych problemów z włączeniem swoich NodeLists do rzeczywistych macierzy, można wykonać następujące czynności, aby osiągnąć pożądany efekt pragnienie:

var allInputs = document.getElementsByTagName("input") 
    , allSelects = document.getElementsByTagName("select") 
;//nodeLists 

var inputList = makeArray(allInputs) 
    , selectList = makeArray(allSelects) 
;//nodeArrays 

var combined = inputList.concat(selectList); 

function makeArray(list){ 
    return Array.prototype.slice.call(list); 
} 

tracisz każdego i wszystkich zachowaniach oryginalny NodeList, w tym możliwość aktualizacji w czasie rzeczywistym w celu odzwierciedlenia zmian w DOM, ale domyślam się, że to nie jest problem.

+0

Należy uprzedzić, że podobnie jak podobne rozwiązanie, które podaję w pierwszej części mojej odpowiedzi, nie będzie to działać w IE8 lub wcześniej. (Wypróbuj tutaj: http://jsbin.com/iledok/1) * wzdycha * Przynajmniej IE9 jest przyzwoity. Tak więc dla IE8 i wcześniejszych potrzebna jest nudna stara pętla. –

1

Co masz do czynienia z są HTMLCollection s, a oni żywo kolekcje (czyli po dodaniu węzła DOM, zostanie on automatycznie dodany do kolekcji.

I niestety, to nie robi „t mieć metodę concat ... bez powodu Co trzeba zrobić, aby przekształcić go do tablicy, tracąc swoje zachowanie na żywo.

var allInputsArray = [].slice.call(allInputs), 
    allSelectsArray = [].slice.call(allSelects), 
    allFields = allInputsArray.concat(allSelectsArray); 
0

znalazłem prosty sposób zbierać przedmioty DOM w kolejności pojawiają się na stronie lub formularzu Najpierw utwórz klasę dummy style "reqd" na obiekcie, a następnie użyj następującego, który tworzy listę w kolejności, w jakiej pojawiają się na stronie. Po prostu dodaj klasę do dowolnych obiektów, które chcesz zebrać.

var allTags = document.querySelectorAll("input.reqd, select.reqd");