Repository: 11ty/eleventy
Pull request #711 (2019-09-26 10:25:08)

Add getFilteredByTags method and tests
Hello everyone,
in the light of #708 I decided to go with the custom collections for now while my amount of tags is still manageable. However, when creating my custom collections I discovered that there is no filter collections by multiple tags either and the `getFilteredByTag` method is not chainable. So I implemented a method that accepts either an array of values to filter by or a single value:

Single value:
Call is forwarded to the existing `getFilteredByTag` method and its result returned. Strictly speaking the method should return an error at this point and but hey this is JS and I'm a generous god ... err developer (_\*insert Xerxes meme\*_).

Array of values:
The method returns an array of elements which contain every value from the input array in its list of tags.

There are currently still errors in the tests but I'm not sure where they are coming from so input is highly appreciated.

Cheers

Edit: Almost forgot to mention, I also trimmed the `getFilteredByTag` methods a bit by switching to array methods instead of using manual comparisons.


Patch:
diff --git a/src/TemplateCollection.js b/src/TemplateCollection.js
index 8c6f0b81..dfc5992c 100644
--- a/src/TemplateCollection.js
+++ b/src/TemplateCollection.js
@@ -50,20 +50,28 @@ class TemplateCollection extends Sortable {
   }
 
   getFilteredByTag(tagName) {
-    return this.getAllSorted().filter(function(item) {
-      let match = false;
+    return this.getAllSorted().filter(item => {
       if (!tagName) {
         return true;
       } else if (Array.isArray(item.data.tags)) {
-        item.data.tags.forEach(tag => {
-          if (tag === tagName) {
-            match = true;
-          }
-        });
+        return item.data.tags.some(tag => tag === tagName);
       }
-      return match;
+      return false;
     });
   }
+
+  getFilteredByTags(...tags) {
+    return this.getAllSorted().filter(item =>
+      tags.every(requiredTag => {
+        const itemTags = item.data.tags;
+        if (Array.isArray(itemTags)) {
+          return itemTags.includes(requiredTag);
+        } else {
+          return itemTags === requiredTag;
+        }
+      })
+    );
+  }
 }
 
 module.exports = TemplateCollection;


Test patch:
diff --git a/test/TemplateCollectionTest.js b/test/TemplateCollectionTest.js
index 842a4e7e..2d0ee6df 100644
--- a/test/TemplateCollectionTest.js
+++ b/test/TemplateCollectionTest.js
@@ -76,6 +76,7 @@ test("getFilteredByTag", async t => {
   let cats = c.getFilteredByTag("cat");
   t.is(cats.length, 2);
   t.deepEqual(cats[0].template, tmpl2);
+  t.deepEqual(cats[1].template, tmpl3);
 
   let dogs = c.getFilteredByTag("dog");
   t.is(dogs.length, 1);
@@ -97,12 +98,56 @@ test("getFilteredByTag (added out of order, sorted)", async t => {
   t.truthy(cats.length);
   t.is(cats.length, 2);
   t.deepEqual(cats[0].template, tmpl2);
+  t.deepEqual(cats[1].template, tmpl3);
 
   let dogs = c.getFilteredByTag("dog");
   t.truthy(dogs.length);
   t.deepEqual(dogs[0].template, tmpl1);
 });
 
+test("getFilteredByTags", async t => {
+  let c = new Collection();
+  await c._testAddTemplate(tmpl1);
+  await c._testAddTemplate(tmpl2);
+  await c._testAddTemplate(tmpl3);
+
+  let postsAndCats = c.getFilteredByTags("post", "cat");
+  t.is(postsAndCats.length, 1);
+  t.deepEqual(postsAndCats[0].template, tmpl3);
+
+  let cats = c.getFilteredByTags("cat");
+  t.is(cats.length, 2);
+  t.deepEqual(cats[0].template, tmpl2);
+  t.deepEqual(cats[1].template, tmpl3);
+
+  let dogs = c.getFilteredByTags("dog");
+  t.is(dogs.length, 1);
+  t.deepEqual(dogs[0].template, tmpl1);
+});
+
+test("getFilteredByTags (added out of order, sorted)", async t => {
+  let c = new Collection();
+  await c._testAddTemplate(tmpl3);
+  await c._testAddTemplate(tmpl2);
+  await c._testAddTemplate(tmpl1);
+
+  let postsAndCats = c.getFilteredByTags("post", "cat");
+  t.truthy(postsAndCats.length);
+  t.is(postsAndCats.length, 1);
+  t.deepEqual(postsAndCats[0].template, tmpl3);
+
+  let cats = c.getFilteredByTags("cat");
+  t.truthy(cats.length);
+  t.is(cats.length, 2);
+  t.deepEqual(cats[0].template, tmpl2);
+  t.deepEqual(cats[1].template, tmpl3);
+
+  let dogs = c.getFilteredByTags("dog");
+  t.truthy(dogs.length);
+  t.is(dogs.length, 1);
+  t.deepEqual(dogs[0].template, tmpl1);
+});
+
 test("getFilteredByGlob", async t => {
   let c = new Collection();
   await c._testAddTemplate(tmpl1);