0

I cannot get Javascript to filter a dynamically created array, although it filters a static array fine. Code block #1 works (static array), code block #2 doesn't (dynamically created array):

// global variables

var globalCalendarEventsArray = [
  {element: "box1", unit: "a"},
  {element: "box2", unit: "a"},
  {element: "box3", unit: "b"},
  {element: "box4", unit: "b"}
];

// var globalCalendarEventsArray = document.getElementsByClassName("redBox");

var rowCalendarEventsArray = [];


// functions
function getRowCalendarEvents (_eventsArray,_unitValue) {
   return _eventsArray.filter(function(_calendarEvent) {
   return _calendarEvent.unit == _unitValue;
  }); 
}

function onMouseDblClick () {
    rowCalendarEventsArray = getRowCalendarEvents(globalCalendarEventsArray,"a");
    alert(globalCalendarEventsArray.length);
    alert(globalCalendarEventsArray[0].unit);
    alert (rowCalendarEventsArray.length);
}


// event listeners
window.addEventListener("dblclick",onMouseDblClick,false);


// execution code
var box1 = document.createElement("div");
box1.className = "redBox";
box1.unit = "a";
document.body.appendChild(box1);

var box2 = document.createElement("div");
box2.className = "redBox";
box2.unit = "a";
document.body.appendChild(box2);

var box3 = document.createElement("div");
box3.className = "redBox";
box3.unit = "b";
document.body.appendChild(box3);

var box4 = document.createElement("div");
box4.className = "redBox";
box4.unit = "b";
document.body.appendChild(box4);

However, as soon as I build the array dynamically by using .getElementsByClassName, the filtering falls apart, despite the alert functions confirming that .getElementsByClassName built an array and that when I call the .unit property it is there. Ex:

// global variables
/*
var globalCalendarEventsArray = [
  {element: "box1", unit: "a"},
  {element: "box2", unit: "a"},
  {element: "box3", unit: "b"},
  {element: "box4", unit: "b"}
];*/

var globalCalendarEventsArray = document.getElementsByClassName("redBox");

var rowCalendarEventsArray = [];


// functions
function getRowCalendarEvents (_eventsArray,_unitValue) {
   return _eventsArray.filter(function(_calendarEvent) {
   return _calendarEvent.unit == _unitValue;
  }); 
}

function onMouseDblClick () {
    rowCalendarEventsArray = getRowCalendarEvents(globalCalendarEventsArray,"a");
    alert(globalCalendarEventsArray.length);
    alert(globalCalendarEventsArray[0].unit);
    alert (rowCalendarEventsArray.length);
}


// event listeners
window.addEventListener("dblclick",onMouseDblClick,false);


// execution code
var box1 = document.createElement("div");
box1.className = "redBox";
box1.unit = "a";
document.body.appendChild(box1);

var box2 = document.createElement("div");
box2.className = "redBox";
box2.unit = "a";
document.body.appendChild(box2);

var box3 = document.createElement("div");
box3.className = "redBox";
box3.unit = "b";
document.body.appendChild(box3);

var box4 = document.createElement("div");
box4.className = "redBox";
box4.unit = "b";
document.body.appendChild(box4);

Fiddle: https://jsfiddle.net/kryman/uexo1hs4/

Any help would be appreciated, thank you.

Kryman
  • 3
  • 5
  • 2
    getElementsByClassName doesn't return an Array, it returns a NodeList. This is an array-like Object but doesn't provide the Array methods. – Thomas Aug 28 '16 at 14:43
  • Thanks @Thomas, I'll play with that and should be able to get it to work. – Kryman Aug 28 '16 at 14:51
  • Possible duplicate of [JS: iterating over result of getElementsByClassName using Array.forEach](http://stackoverflow.com/questions/3871547/js-iterating-over-result-of-getelementsbyclassname-using-array-foreach) – trincot Aug 28 '16 at 14:52
  • @trincot, why messing around like this? this is one of these tools that you'll need all over the place. Write a little utility `function $$(selector, ctx){ return Array.from((ctx && ctx.querySelectorAll? ctx: document).querySelectorAll(selector)) }` and use it `var globalCalendarEventsArray = $$(".redBox")` – Thomas Aug 28 '16 at 15:20
  • @Thomas, was that comment for me? I am messing around? – trincot Aug 28 '16 at 15:54
  • @trincot it was about the code/approach you linked. `Array.prototype.forEach.call(arrayLike, fn)` that's what I mean with messing around. It has its use cases, but for this particular one, it's too complicated/verbose; especially considering that most likely you'll have to use it multiple times in your code, not just once. That's what I actually meant. Sorry, didn't mean to offend you. And Kryman automatically gets notified, don't have to reference him, so he reads the comment. – Thomas Aug 28 '16 at 16:38
  • @Thomas, I only marked this question as duplicate, since this has been asked several times before in several flavours. If the answers to the linked question are insufficient to your taste, feel free to post your own there. – trincot Aug 28 '16 at 16:40

2 Answers2

0

_eventsArray in your second example is an HTMLCollection not a JS Array. You can convert it like the following:

function getRowCalendarEvents (_eventsArray,_unitValue) {
    var arr = [].slice.call(_eventsArray);

    return arr.filter(function(_calendarEvent) {
    return _calendarEvent.unit == _unitValue;
  }); 
}
Will M
  • 2,135
  • 4
  • 22
  • 32
  • 1
    In ES6, you can also use [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) to convert the array-like object to an actual array. – qxz Aug 28 '16 at 15:07
0

Or, we can actually do

Array.prototype.filter.call(_eventsArray, function(_calendarEvent) {
   return _calendarEvent.unit == _unitValue;
});
Pang
  • 9,564
  • 146
  • 81
  • 122
Ivan Shmidt
  • 163
  • 1
  • 7