diff --git a/examples/webpack-demo-vanilla-bundle/src/examples/example07.html b/examples/webpack-demo-vanilla-bundle/src/examples/example07.html
index 2b81f7ff3..ceaf67703 100644
--- a/examples/webpack-demo-vanilla-bundle/src/examples/example07.html
+++ b/examples/webpack-demo-vanilla-bundle/src/examples/example07.html
@@ -23,6 +23,7 @@ <h3 class="title is-3">
     <span class="icon mdi mdi-sort-variant-remove"></span>
     <span>Disable Sorting</span>
   </button>
+  <div style="margin: 5px 0"></div>
   <button class="button is-small" data-test="toggle-filtering-btn" onclick.delegate="toggleFilter()">
     <span class="icon mdi mdi-swap-vertical"></span>
     <span>Toggle Filtering</span>
@@ -31,6 +32,17 @@ <h3 class="title is-3">
     <span class="icon mdi mdi-swap-vertical"></span>
     <span>Toggle Sorting</span>
   </button>
+
+  <button class="button is-small" data-test="add-item-btn" onclick.delegate="addItem()"
+          title="Clear Filters &amp; Sorting to see it better">
+    <span class="icon mdi mdi-plus"></span>
+    <span>Add item</span>
+  </button>
+  <button class="button is-small" data-test="delete-item-btn" onclick.delegate="deleteItem()">
+    <span class="icon mdi mdi-minus"></span>
+    <span>Delete item</span>
+  </button>
+
 </div>
 
 <br />
diff --git a/examples/webpack-demo-vanilla-bundle/src/examples/example07.ts b/examples/webpack-demo-vanilla-bundle/src/examples/example07.ts
index 39b3bd2a0..7d70a9213 100644
--- a/examples/webpack-demo-vanilla-bundle/src/examples/example07.ts
+++ b/examples/webpack-demo-vanilla-bundle/src/examples/example07.ts
@@ -2,10 +2,11 @@ import {
   BindingEventService,
   Column,
   Editors,
+  FieldType,
   Filters,
   Formatters,
-  FieldType,
   GridOption,
+  OperatorType,
 } from '@slickgrid-universal/common';
 import { ExcelExportService } from '@slickgrid-universal/excel-export';
 import { Slicker, SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bundle';
@@ -79,6 +80,81 @@ export class Example7 {
             resolve([{ value: true, label: 'True' }, { value: false, label: 'False' }]);
           }, 250)),
         },
+      },
+      {
+        id: 'prerequisites',
+        name: 'Prerequisites',
+        field: 'prerequisites',
+        filterable: true,
+        formatter: (_row, _cell, value) => {
+          if (value && Array.isArray(value)) {
+            const values = value.map((val) => `Task ${val}`).join(', ');
+            return `<span title="${values}">${values}</span>`;
+          }
+          return '';
+        },
+        exportWithFormatter: true,
+        sanitizeDataExport: true,
+        minWidth: 100,
+        sortable: true,
+        type: FieldType.string,
+        editor: {
+          // We can load the "collection" asynchronously (on first load only, after that we will simply use "collection")
+          // 2 ways are supported (aurelia-http-client, aurelia-fetch-client OR even Promise)
+
+          // OR 1- use "aurelia-fetch-client", they are both supported
+          // collectionAsync: fetch(URL_SAMPLE_COLLECTION_DATA),
+
+          // OR 2- use a Promise
+          collectionAsync: new Promise<any>((resolve) => {
+            setTimeout(() => {
+              resolve(Array.from(Array(this.dataset.length).keys()).map(k => ({ value: k, label: k, prefix: 'Task', suffix: 'days' })));
+            }, 500);
+          }),
+
+          // OR a regular "collection" load
+          // collection: Array.from(Array(NB_ITEMS).keys()).map(k => ({ value: k, label: k, prefix: 'Task', suffix: 'days' })),
+          collectionSortBy: {
+            property: 'value',
+            sortDesc: true,
+            fieldType: FieldType.number
+          },
+          customStructure: {
+            label: 'label',
+            value: 'value',
+            labelPrefix: 'prefix',
+          },
+          collectionOptions: {
+            separatorBetweenTextLabels: ' '
+          },
+          model: Editors.multipleSelect,
+        },
+        filter: {
+          // collectionAsync: fetch(URL_SAMPLE_COLLECTION_DATA),
+          collectionAsync: new Promise((resolve) => {
+            setTimeout(() => {
+              resolve(Array.from(Array(this.dataset.length).keys()).map(k => ({ value: k, label: `Task ${k}` })));
+            });
+          }),
+
+          // OR a regular collection load
+          // collection: Array.from(Array(NB_ITEMS).keys()).map(k => ({ value: k, label: k, prefix: 'Task', suffix: 'days' })),
+          collectionSortBy: {
+            property: 'value',
+            sortDesc: true,
+            fieldType: FieldType.number
+          },
+          customStructure: {
+            label: 'label',
+            value: 'value',
+            labelPrefix: 'prefix',
+          },
+          collectionOptions: {
+            separatorBetweenTextLabels: ' '
+          },
+          model: Filters.multipleSelect,
+          operator: OperatorType.inContains,
+        },
       }
     ];
 
@@ -132,21 +208,73 @@ export class Example7 {
     };
   }
 
-  loadData(rowCount: number) {
+  /** Add a new row to the grid and refresh the Filter collection */
+  addItem() {
+    const lastRowIndex = this.dataset.length;
+    const newRows = this.loadData(1, lastRowIndex);
+
+    // wrap into a timer to simulate a backend async call
+    setTimeout(() => {
+      // at any time, we can poke the "collection" property and modify it
+      const requisiteColumnDef = this.columnDefinitions.find((column: Column) => column.id === 'prerequisites');
+      if (requisiteColumnDef) {
+        const collectionEditor = requisiteColumnDef.editor.collection;
+        const collectionFilter = requisiteColumnDef.filter.collection;
+
+        if (Array.isArray(collectionEditor) && Array.isArray(collectionFilter)) {
+          // add the new row to the grid
+          this.sgb.gridService.addItem(newRows[0], { highlightRow: false });
+
+          // then refresh the Editor/Filter "collection", we have 2 ways of doing it
+
+          // 1- push to the "collection"
+          collectionEditor.push({ value: lastRowIndex, label: lastRowIndex, prefix: 'Task', suffix: 'days' });
+          collectionFilter.push({ value: lastRowIndex, label: lastRowIndex, prefix: 'Task', suffix: 'days' });
+
+          // OR 2- replace the entire "collection" is also supported
+          // requisiteColumnDef.filter.collection = [...requisiteColumnDef.filter.collection, ...[{ value: lastRowIndex, label: lastRowIndex, prefix: 'Task' }]];
+          // requisiteColumnDef.editor.collection = [...requisiteColumnDef.editor.collection, ...[{ value: lastRowIndex, label: lastRowIndex, prefix: 'Task' }]];
+        }
+      }
+    }, 50);
+  }
+
+  /** Delete last inserted row */
+  deleteItem() {
+    const requisiteColumnDef = this.columnDefinitions.find((column: Column) => column.id === 'prerequisites');
+    if (requisiteColumnDef) {
+      const collectionEditor = requisiteColumnDef.editor.collection;
+      const collectionFilter = requisiteColumnDef.filter.collection;
+
+      if (Array.isArray(collectionEditor) && Array.isArray(collectionFilter)) {
+        // sort collection in descending order and take out last option from the collection
+        const selectCollectionObj = this.sortCollectionDescending(collectionEditor).pop();
+        this.sortCollectionDescending(collectionFilter).pop();
+        this.sgb.gridService.deleteItemById(selectCollectionObj.value);
+      }
+    }
+  }
+
+  loadData(itemCount: number, startingIndex = 0) {
     // Set up some test columns.
-    const mockDataset = [];
-    for (let i = 0; i < rowCount; i++) {
-      mockDataset[i] = {
+    const tempDataset = [];
+    for (let i = startingIndex; i < (startingIndex + itemCount); i++) {
+      tempDataset.push({
         id: i,
         title: 'Task ' + i,
         duration: Math.round(Math.random() * 25),
         percentComplete: Math.round(Math.random() * 100),
         start: new Date(2009, 0, 1),
         finish: new Date(2009, 0, 5),
-        effortDriven: (i % 5 === 0)
-      };
+        effortDriven: (i % 5 === 0),
+        prerequisites: (i % 2 === 0) && i !== 0 && i < 12 ? [i, i - 1] : [],
+      });
     }
-    return mockDataset;
+    return tempDataset;
+  }
+
+  sortCollectionDescending(collection) {
+    return collection.sort((item1, item2) => item1.value - item2.value);
   }
 
   onBeforeMoveRow(e, data) {
diff --git a/package.json b/package.json
index bd2b1e806..42216e8c9 100644
--- a/package.json
+++ b/package.json
@@ -52,7 +52,7 @@
     "@types/node": "^14.14.14",
     "@typescript-eslint/eslint-plugin": "^4.10.0",
     "@typescript-eslint/parser": "^4.10.0",
-    "cypress": "^6.1.0",
+    "cypress": "^6.2.0",
     "eslint": "^7.15.0",
     "eslint-plugin-import": "^2.22.1",
     "eslint-plugin-prefer-arrow": "^1.2.2",
@@ -75,4 +75,4 @@
     "node": ">=12.0.0",
     "npm": ">=6.14.0"
   }
-}
\ No newline at end of file
+}
diff --git a/packages/common/src/filters/__tests__/autoCompleteFilter.spec.ts b/packages/common/src/filters/__tests__/autoCompleteFilter.spec.ts
index 8c863280c..b2fc357a5 100644
--- a/packages/common/src/filters/__tests__/autoCompleteFilter.spec.ts
+++ b/packages/common/src/filters/__tests__/autoCompleteFilter.spec.ts
@@ -6,6 +6,8 @@ import { CollectionService } from '../../services/collection.service';
 import { HttpStub } from '../../../../../test/httpClientStub';
 import { TranslateServiceStub } from '../../../../../test/translateServiceStub';
 
+jest.useFakeTimers();
+
 const containerId = 'demo-container';
 
 // define a <div> container to simulate the grid container
@@ -86,14 +88,6 @@ describe('AutoCompleteFilter', () => {
     }
   });
 
-  it('should throw an error when "collectionAsync" Promise does not return a valid array', (done) => {
-    mockColumn.filter!.collectionAsync = Promise.resolve({ hello: 'world' });
-    filter.init(filterArguments).catch((e) => {
-      expect(e.toString()).toContain(`Something went wrong while trying to pull the collection from the "collectionAsync" call in the AutoComplete Filter, the collection is not a valid array.`);
-      done();
-    });
-  });
-
   it('should initialize the filter', () => {
     mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }];
     filter.init(filterArguments);
@@ -249,55 +243,49 @@ describe('AutoCompleteFilter', () => {
     expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, clearFilterTriggered: true, shouldTriggerQuery: false });
   });
 
-  it('should create the filter with a default search term when using "collectionAsync" as a Promise', (done) => {
+  it('should create the filter with a default search term when using "collectionAsync" as a Promise', async () => {
     const spyCallback = jest.spyOn(filterArguments, 'callback');
     const mockCollection = ['male', 'female'];
     mockColumn.filter!.collectionAsync = Promise.resolve(mockCollection);
 
     filterArguments.searchTerms = ['female'];
-    filter.init(filterArguments);
+    await filter.init(filterArguments);
 
-    setTimeout(() => {
-      const filterElm = divContainer.querySelector('input.filter-gender') as HTMLInputElement;
-      const autocompleteUlElms = document.body.querySelectorAll<HTMLUListElement>('ul.ui-autocomplete');
-      filter.setValues('male');
+    const filterElm = divContainer.querySelector('input.filter-gender') as HTMLInputElement;
+    const autocompleteUlElms = document.body.querySelectorAll<HTMLUListElement>('ul.ui-autocomplete');
+    filter.setValues('male');
 
-      filterElm.focus();
-      filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('input', { keyCode: 97, bubbles: true, cancelable: true }));
-      const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-gender.filled');
+    filterElm.focus();
+    filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('input', { keyCode: 97, bubbles: true, cancelable: true }));
+    const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-gender.filled');
 
-      expect(autocompleteUlElms.length).toBe(1);
-      expect(filterFilledElms.length).toBe(1);
-      expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['male'], shouldTriggerQuery: true });
-      done();
-    });
+    expect(autocompleteUlElms.length).toBe(1);
+    expect(filterFilledElms.length).toBe(1);
+    expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['male'], shouldTriggerQuery: true });
   });
 
-  it('should create the filter with a default search term when using "collectionAsync" as a Promise with content to simulate http-client', (done) => {
+  it('should create the filter with a default search term when using "collectionAsync" as a Promise with content to simulate http-client', async () => {
     const spyCallback = jest.spyOn(filterArguments, 'callback');
     const mockCollection = ['male', 'female'];
     mockColumn.filter!.collectionAsync = Promise.resolve({ content: mockCollection });
 
     filterArguments.searchTerms = ['female'];
-    filter.init(filterArguments);
+    await filter.init(filterArguments);
 
-    setTimeout(() => {
-      const filterElm = divContainer.querySelector('input.filter-gender') as HTMLInputElement;
-      const autocompleteUlElms = document.body.querySelectorAll<HTMLUListElement>('ul.ui-autocomplete');
-      filter.setValues('male');
+    const filterElm = divContainer.querySelector('input.filter-gender') as HTMLInputElement;
+    const autocompleteUlElms = document.body.querySelectorAll<HTMLUListElement>('ul.ui-autocomplete');
+    filter.setValues('male');
 
-      filterElm.focus();
-      filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('input', { keyCode: 97, bubbles: true, cancelable: true }));
-      const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-gender.filled');
+    filterElm.focus();
+    filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('input', { keyCode: 97, bubbles: true, cancelable: true }));
+    const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-gender.filled');
 
-      expect(autocompleteUlElms.length).toBe(1);
-      expect(filterFilledElms.length).toBe(1);
-      expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['male'], shouldTriggerQuery: true });
-      done();
-    });
+    expect(autocompleteUlElms.length).toBe(1);
+    expect(filterFilledElms.length).toBe(1);
+    expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['male'], shouldTriggerQuery: true });
   });
 
-  it('should create the filter with a default search term when using "collectionAsync" is a Fetch Promise', (done) => {
+  it('should create the filter with a default search term when using "collectionAsync" is a Fetch Promise', async () => {
     const spyCallback = jest.spyOn(filterArguments, 'callback');
     const mockCollection = ['male', 'female'];
 
@@ -309,22 +297,19 @@ describe('AutoCompleteFilter', () => {
     mockColumn.filter!.collectionAsync = http.fetch('/api', { method: 'GET' });
 
     filterArguments.searchTerms = ['female'];
-    filter.init(filterArguments);
+    await filter.init(filterArguments);
 
-    setTimeout(() => {
-      const filterElm = divContainer.querySelector('input.filter-gender') as HTMLInputElement;
-      const autocompleteUlElms = document.body.querySelectorAll<HTMLUListElement>('ul.ui-autocomplete');
-      filter.setValues('male');
+    const filterElm = divContainer.querySelector('input.filter-gender') as HTMLInputElement;
+    const autocompleteUlElms = document.body.querySelectorAll<HTMLUListElement>('ul.ui-autocomplete');
+    filter.setValues('male');
 
-      filterElm.focus();
-      filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('input', { keyCode: 97, bubbles: true, cancelable: true }));
-      const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-gender.filled');
+    filterElm.focus();
+    filterElm.dispatchEvent(new (window.window as any).KeyboardEvent('input', { keyCode: 97, bubbles: true, cancelable: true }));
+    const filterFilledElms = divContainer.querySelectorAll<HTMLInputElement>('input.filter-gender.filled');
 
-      expect(autocompleteUlElms.length).toBe(1);
-      expect(filterFilledElms.length).toBe(1);
-      expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['male'], shouldTriggerQuery: true });
-      done();
-    });
+    expect(autocompleteUlElms.length).toBe(1);
+    expect(filterFilledElms.length).toBe(1);
+    expect(spyCallback).toHaveBeenCalledWith(expect.anything(), { columnDef: mockColumn, operator: 'EQ', searchTerms: ['male'], shouldTriggerQuery: true });
   });
 
   it('should create the filter and filter the string collection when "collectionFilterBy" is set', () => {
@@ -410,25 +395,25 @@ describe('AutoCompleteFilter', () => {
     expect(filterCollection[2]).toEqual({ value: 'female', description: 'female' });
   });
 
-  it('should create the filter with a value/label pair collectionAsync that is inside an object when "collectionInsideObjectProperty" is defined with a dot notation', (done) => {
-    const mockCollection = { deep: { myCollection: [{ value: 'other', description: 'other' }, { value: 'male', description: 'male' }, { value: 'female', description: 'female' }] } };
-    mockColumn.filter = {
-      collectionAsync: Promise.resolve(mockCollection),
-      collectionOptions: { collectionInsideObjectProperty: 'deep.myCollection' },
-      customStructure: { value: 'value', label: 'description', },
-    };
-
-    filter.init(filterArguments);
+  it('should create the filter with a value/label pair collectionAsync that is inside an object when "collectionInsideObjectProperty" is defined with a dot notation', async () => {
+    try {
+      const mockCollection = { deep: { myCollection: [{ value: 'other', description: 'other' }, { value: 'male', description: 'male' }, { value: 'female', description: 'female' }] } };
+      mockColumn.filter = {
+        collectionAsync: Promise.resolve(mockCollection),
+        collectionOptions: { collectionInsideObjectProperty: 'deep.myCollection' },
+        customStructure: { value: 'value', label: 'description', },
+      };
 
-    setTimeout(() => {
+      await filter.init(filterArguments);
       const filterCollection = filter.collection as any[];
 
       expect(filterCollection.length).toBe(3);
       expect(filterCollection[0]).toEqual({ value: 'other', description: 'other' });
       expect(filterCollection[1]).toEqual({ value: 'male', description: 'male' });
       expect(filterCollection[2]).toEqual({ value: 'female', description: 'female' });
-      done();
-    }, 2);
+    } catch (e) {
+      console.log('ERROR', e)
+    }
   });
 
   it('should create the filter and sort the string collection when "collectionSortBy" is set', () => {
@@ -534,27 +519,44 @@ describe('AutoCompleteFilter', () => {
       expect(spy).toHaveBeenCalledWith(event, { item: 'fem' });
     });
 
-    it('should expect the "onSelect" method to be called when the callback method is triggered', () => {
-      const spy = jest.spyOn(filter, 'onSelect');
-      const event = new CustomEvent('change');
+    it('should trigger a re-render of the DOM element when collection is replaced by new collection', async () => {
+      const renderSpy = jest.spyOn(filter, 'renderDomElement');
+      const newCollection = [{ value: 'val1', label: 'label1' }, { value: 'val2', label: 'label2' }];
+      const mockDataResponse = [{ value: 'female', label: 'Female' }, { value: 'male', label: 'Male' }];
 
-      mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }];
-      filter.init(filterArguments);
-      filter.autoCompleteOptions!.select!(event, { item: 'fem' });
+      mockColumn.filter = {
+        collection: [],
+        collectionAsync: Promise.resolve(mockDataResponse),
+        enableCollectionWatch: true,
+      };
 
-      expect(spy).toHaveBeenCalledWith(event, { item: 'fem' });
+      await filter.init(filterArguments);
+      mockColumn.filter!.collection = newCollection;
+      mockColumn.filter!.collection!.push({ value: 'val3', label: 'label3' });
+
+      jest.runAllTimers(); // fast-forward timer]
+
+      expect(renderSpy).toHaveBeenCalledTimes(3);
+      expect(renderSpy).toHaveBeenCalledWith(newCollection);
     });
 
-    it('should initialize the filter with filterOptions and expect the "onSelect" method to be called when the callback method is triggered', () => {
-      const spy = jest.spyOn(filter, 'onSelect');
-      const event = new CustomEvent('change');
+    it('should trigger a re-render of the DOM element when collection changes', async () => {
+      const renderSpy = jest.spyOn(filter, 'renderDomElement');
+      const mockDataResponse = [{ value: 'female', label: 'Female' }, { value: 'male', label: 'Male' }];
 
-      mockColumn.filter!.collection = [{ value: 'male', label: 'male' }, { value: 'female', label: 'female' }];
-      mockColumn.filter!.filterOptions = { minLength: 3 } as AutocompleteOption;
-      filter.init(filterArguments);
-      filter.autoCompleteOptions!.select!(event, { item: 'fem' });
+      mockColumn.filter = {
+        collection: [],
+        collectionAsync: new Promise((resolve) => resolve(mockDataResponse)),
+        enableCollectionWatch: true,
+      };
 
-      expect(spy).toHaveBeenCalledWith(event, { item: 'fem' });
+      await filter.init(filterArguments);
+      mockColumn.filter!.collection!.push({ value: 'other', label: 'other' });
+
+      jest.runAllTimers(); // fast-forward timer
+
+      expect(renderSpy).toHaveBeenCalledTimes(2);
+      expect(renderSpy).toHaveBeenCalledWith(mockColumn.filter!.collection);
     });
   });
 
@@ -645,5 +647,14 @@ describe('AutoCompleteFilter', () => {
       const liElm = ulElm.querySelector('li') as HTMLLIElement;
       expect(liElm.innerHTML).toBe(mockTemplateString);
     });
+
+    it('should throw an error when "collectionAsync" Promise does not return a valid array', (done) => {
+      const promise = Promise.resolve({ hello: 'world' });
+      mockColumn.filter!.collectionAsync = promise;
+      filter.init(filterArguments).catch((e) => {
+        expect(e.toString()).toContain(`Something went wrong while trying to pull the collection from the "collectionAsync" call in the AutoComplete Filter, the collection is not a valid array.`);
+        done();
+      });
+    });
   });
 });
diff --git a/packages/common/src/filters/__tests__/selectFilter.spec.ts b/packages/common/src/filters/__tests__/selectFilter.spec.ts
index defe3bd6c..7e4fcd24e 100644
--- a/packages/common/src/filters/__tests__/selectFilter.spec.ts
+++ b/packages/common/src/filters/__tests__/selectFilter.spec.ts
@@ -64,7 +64,6 @@ describe('SelectFilter', () => {
   });
 
   afterEach(() => {
-    mockColumn.filter = undefined;
     filter.destroy();
     jest.clearAllMocks();
   });
@@ -732,6 +731,62 @@ describe('SelectFilter', () => {
     expect(filterListElm[2].textContent).toBe('female');
   });
 
+  it('should trigger a re-render of the DOM element when collection is replaced by new collection', async () => {
+    const renderSpy = jest.spyOn(filter, 'renderDomElement');
+    const newCollection = [{ value: 'val1', label: 'label1' }, { value: 'val2', label: 'label2' }];
+    const mockDataResponse = [{ value: 'female', label: 'Female' }, { value: 'male', label: 'Male' }];
+
+    mockColumn.filter = {
+      collection: [],
+      collectionAsync: Promise.resolve(mockDataResponse),
+      enableCollectionWatch: true,
+    };
+
+    await filter.init(filterArguments);
+    mockColumn.filter!.collection = newCollection;
+    mockColumn.filter!.collection!.push({ value: 'val3', label: 'label3' });
+
+    jest.runAllTimers(); // fast-forward timer
+
+    expect(renderSpy).toHaveBeenCalledTimes(3);
+    expect(renderSpy).toHaveBeenCalledWith(newCollection);
+
+    const filterBtnElm = divContainer.querySelector('.ms-parent.ms-filter.search-filter.filter-gender button.ms-choice') as HTMLButtonElement;
+    const filterListElm = divContainer.querySelectorAll<HTMLSpanElement>(`[name=filter-gender].ms-drop ul>li span`);
+    filterBtnElm.click();
+
+    expect(filterListElm.length).toBe(3);
+    expect(filterListElm[0].textContent).toBe('label1');
+    expect(filterListElm[1].textContent).toBe('label2');
+    expect(filterListElm[2].textContent).toBe('label3');
+  });
+
+  it('should trigger a re-render of the DOM element when collection changes', async () => {
+    const renderSpy = jest.spyOn(filter, 'renderDomElement');
+
+    mockColumn.filter = {
+      collection: [{ value: 'female', label: 'Female' }, { value: 'male', label: 'Male' }],
+      enableCollectionWatch: true,
+    };
+
+    await filter.init(filterArguments);
+    mockColumn.filter!.collection!.push({ value: 'other', label: 'Other' });
+
+    jest.runAllTimers(); // fast-forward timer
+
+    expect(renderSpy).toHaveBeenCalledTimes(2);
+    expect(renderSpy).toHaveBeenCalledWith(mockColumn.filter!.collection);
+
+    const filterBtnElm = divContainer.querySelector('.ms-parent.ms-filter.search-filter.filter-gender button.ms-choice') as HTMLButtonElement;
+    const filterListElm = divContainer.querySelectorAll<HTMLSpanElement>(`[name=filter-gender].ms-drop ul>li span`);
+    filterBtnElm.click();
+
+    expect(filterListElm.length).toBe(3);
+    expect(filterListElm[0].textContent).toBe('Female');
+    expect(filterListElm[1].textContent).toBe('Male');
+    expect(filterListElm[2].textContent).toBe('Other');
+  });
+
   it('should throw an error when "collectionAsync" Promise does not return a valid array', async (done) => {
     const promise = Promise.resolve({ hello: 'world' });
     mockColumn.filter!.collectionAsync = promise;
@@ -743,4 +798,13 @@ describe('SelectFilter', () => {
       done();
     }
   });
+
+  it('should throw an error when "collectionAsync" Promise does not return a valid array', (done) => {
+    const promise = Promise.resolve({ hello: 'world' });
+    mockColumn.filter!.collectionAsync = promise;
+    filter.init(filterArguments).catch((e) => {
+      expect(e.toString()).toContain(`Something went wrong while trying to pull the collection from the "collectionAsync" call in the Select Filter, the collection is not a valid array.`);
+      done();
+    });
+  });
 });
diff --git a/packages/common/src/filters/autoCompleteFilter.ts b/packages/common/src/filters/autoCompleteFilter.ts
index 4631e273e..2f16cecaa 100644
--- a/packages/common/src/filters/autoCompleteFilter.ts
+++ b/packages/common/src/filters/autoCompleteFilter.ts
@@ -19,6 +19,7 @@ import {
   SlickGrid,
 } from './../interfaces/index';
 import { CollectionService } from '../services/collection.service';
+import { collectionObserver, propertyObserver } from '../services/observers';
 import { getDescendantProperty, sanitizeTextByAvailableSanitizer, toKebabCase } from '../services/utilities';
 import { TranslaterService } from '../services/translater.service';
 
@@ -158,14 +159,29 @@ export class AutoCompleteFilter implements Filter {
     this._collection = newCollection;
     this.renderDomElement(newCollection);
 
-    return new Promise(resolve => {
-      const collectionAsync = this.columnFilter.collectionAsync;
-      if (collectionAsync && !this.columnFilter.collection) {
-        // only read the collectionAsync once (on the 1st load),
-        // we do this because Http Fetch will throw an error saying body was already read and is streaming is locked
-        resolve(this.renderOptionsAsync(collectionAsync));
-      } else {
-        resolve(newCollection);
+    return new Promise(async (resolve, reject) => {
+      try {
+        const collectionAsync = this.columnFilter.collectionAsync;
+        let collectionOutput: Promise<any[]> | any[] | undefined;
+
+        if (collectionAsync && !this.columnFilter.collection) {
+          // only read the collectionAsync once (on the 1st load),
+          // we do this because Http Fetch will throw an error saying body was already read and is streaming is locked
+          collectionOutput = this.renderOptionsAsync(collectionAsync);
+          resolve(collectionOutput);
+        } else {
+          collectionOutput = newCollection;
+          resolve(newCollection);
+        }
+
+        // subscribe to both CollectionObserver and PropertyObserver
+        // any collection changes will trigger a re-render of the DOM element filter
+        if (collectionAsync || this.columnFilter.enableCollectionWatch) {
+          await (collectionOutput ?? collectionAsync);
+          this.watchCollectionChanges();
+        }
+      } catch (e) {
+        reject(e);
       }
     });
   }
@@ -244,6 +260,33 @@ export class AutoCompleteFilter implements Filter {
     return outputCollection;
   }
 
+  /**
+   * Subscribe to both CollectionObserver & PropertyObserver with BindingEngine.
+   * They each have their own purpose, the "propertyObserver" will trigger once the collection is replaced entirely
+   * while the "collectionObverser" will trigger on collection changes (`push`, `unshift`, `splice`, ...)
+   */
+  protected watchCollectionChanges() {
+    if (this.columnFilter?.collection) {
+      // subscribe to the "collection" changes (array `push`, `unshift`, `splice`, ...)
+      collectionObserver(this.columnFilter.collection, (updatedArray) => {
+        this.renderDomElement(this.columnFilter.collection || updatedArray || []);
+      });
+
+      // observe for any "collection" changes (array replace)
+      // then simply recreate/re-render the Select (dropdown) DOM Element
+      propertyObserver(this.columnFilter, 'collection', (newValue) => {
+        this.renderDomElement(newValue || []);
+
+        // when new assignment arrives, we need to also reassign observer to the new reference
+        if (this.columnFilter.collection) {
+          collectionObserver(this.columnFilter.collection, (updatedArray) => {
+            this.renderDomElement(this.columnFilter.collection || updatedArray || []);
+          });
+        }
+      });
+    }
+  }
+
   renderDomElement(collection: any[]) {
     if (!Array.isArray(collection) && this.collectionOptions?.collectionInsideObjectProperty) {
       const collectionInsideObjectProperty = this.collectionOptions.collectionInsideObjectProperty;
diff --git a/packages/common/src/filters/selectFilter.ts b/packages/common/src/filters/selectFilter.ts
index af85f77b0..180cbb7c3 100644
--- a/packages/common/src/filters/selectFilter.ts
+++ b/packages/common/src/filters/selectFilter.ts
@@ -15,6 +15,7 @@ import {
   SlickGrid
 } from './../interfaces/index';
 import { CollectionService } from '../services/collection.service';
+import { collectionObserver, propertyObserver } from '../services/observers';
 import { getDescendantProperty, getTranslationPrefix, htmlEncode, sanitizeTextByAvailableSanitizer } from '../services/utilities';
 import { TranslaterService } from '../services';
 
@@ -140,17 +141,29 @@ export class SelectFilter implements Filter {
     const newCollection = this.columnFilter.collection || [];
     this.renderDomElement(newCollection);
 
-    // return new Promise(resolve => resolve(newCollection));
-
-    return new Promise(async resolve => {
-      const collectionAsync = this.columnFilter.collectionAsync;
-
-      if (collectionAsync && !this.columnFilter.collection) {
-        // only read the collectionAsync once (on the 1st load),
-        // we do this because Http Fetch will throw an error saying body was already read and its streaming is locked
-        resolve(this.renderOptionsAsync(collectionAsync));
-      } else {
-        resolve(newCollection);
+    return new Promise(async (resolve, reject) => {
+      try {
+        const collectionAsync = this.columnFilter.collectionAsync;
+        let collectionOutput: Promise<any[]> | any[] | undefined;
+
+        if (collectionAsync && !this.columnFilter.collection) {
+          // only read the collectionAsync once (on the 1st load),
+          // we do this because Http Fetch will throw an error saying body was already read and its streaming is locked
+          collectionOutput = this.renderOptionsAsync(collectionAsync);
+          resolve(collectionOutput);
+        } else {
+          collectionOutput = newCollection;
+          resolve(newCollection);
+        }
+
+        // subscribe to both CollectionObserver and PropertyObserver
+        // any collection changes will trigger a re-render of the DOM element filter
+        if (collectionAsync || this.columnFilter.enableCollectionWatch) {
+          await (collectionOutput ?? collectionAsync);
+          this.watchCollectionChanges();
+        }
+      } catch (e) {
+        reject(e);
       }
     });
   }
@@ -244,6 +257,33 @@ export class SelectFilter implements Filter {
     return outputCollection;
   }
 
+  /**
+   * Subscribe to both CollectionObserver & PropertyObserver with BindingEngine.
+   * They each have their own purpose, the "propertyObserver" will trigger once the collection is replaced entirely
+   * while the "collectionObverser" will trigger on collection changes (`push`, `unshift`, `splice`, ...)
+   */
+  protected watchCollectionChanges() {
+    if (this.columnFilter?.collection) {
+      // subscribe to the "collection" changes (array `push`, `unshift`, `splice`, ...)
+      collectionObserver(this.columnFilter.collection, (updatedArray) => {
+        this.renderDomElement(this.columnFilter.collection || updatedArray || []);
+      });
+
+      // observe for any "collection" changes (array replace)
+      // then simply recreate/re-render the Select (dropdown) DOM Element
+      propertyObserver(this.columnFilter, 'collection', (newValue) => {
+        this.renderDomElement(newValue || []);
+
+        // when new assignment arrives, we need to also reassign observer to the new reference
+        if (this.columnFilter.collection) {
+          collectionObserver(this.columnFilter.collection, (updatedArray) => {
+            this.renderDomElement(this.columnFilter.collection || updatedArray || []);
+          });
+        }
+      });
+    }
+  }
+
   renderDomElement(inputCollection: any[]) {
     if (!Array.isArray(inputCollection) && this.collectionOptions?.collectionInsideObjectProperty) {
       const collectionInsideObjectProperty = this.collectionOptions.collectionInsideObjectProperty;
@@ -302,10 +342,10 @@ export class SelectFilter implements Filter {
   protected buildTemplateHtmlString(optionCollection: any[], searchTerms: SearchTerm[]): string {
     let options = '';
     const columnId = this.columnDef?.id ?? '';
-    const separatorBetweenLabels = this.collectionOptions && this.collectionOptions.separatorBetweenTextLabels || '';
-    const isTranslateEnabled = this.gridOptions && this.gridOptions.enableTranslate;
-    const isRenderHtmlEnabled = this.columnFilter && this.columnFilter.enableRenderHtml || false;
-    const sanitizedOptions = this.gridOptions && this.gridOptions.sanitizeHtmlOptions || {};
+    const separatorBetweenLabels = this.collectionOptions?.separatorBetweenTextLabels ?? '';
+    const isTranslateEnabled = this.gridOptions?.enableTranslate ?? false;
+    const isRenderHtmlEnabled = this.columnFilter?.enableRenderHtml ?? false;
+    const sanitizedOptions = this.gridOptions?.sanitizeHtmlOptions ?? {};
 
     // collection could be an Array of Strings OR Objects
     if (Array.isArray(optionCollection)) {
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index 6dfd90b86..20d014e63 100644
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -1,6 +1,7 @@
 import 'multiple-select-modified';
 
 import * as BackendUtilities from './services/backend-utilities';
+import * as Observers from './services/observers';
 import * as ServiceUtilities from './services/utilities';
 import * as SortUtilities from './sortComparers/sortUtilities';
 
@@ -28,6 +29,6 @@ export * from './sortComparers/sortComparers.index';
 export * from './services/index';
 export { Enums } from './enums/enums.index';
 
-const Utilities = { ...BackendUtilities, ...ServiceUtilities, ...SortUtilities };
+const Utilities = { ...BackendUtilities, ...Observers, ...ServiceUtilities, ...SortUtilities };
 export { Utilities };
 export { SlickgridConfig } from './slickgrid-config';
diff --git a/packages/common/src/services/__tests__/observers.spec.ts b/packages/common/src/services/__tests__/observers.spec.ts
new file mode 100644
index 000000000..b76378d50
--- /dev/null
+++ b/packages/common/src/services/__tests__/observers.spec.ts
@@ -0,0 +1,99 @@
+import {
+  collectionObserver,
+  propertyObserver,
+} from '../observers';
+
+describe('Service/Observers', () => {
+  describe('collectionObserver method', () => {
+    it('should watch for array "pop" change and expect callback to be executed', (done) => {
+      const expectation: any[] = [{ value: true, label: 'True' }, { value: false, label: 'False' }];
+      const inputArray = [{ value: true, label: 'True' }, { value: false, label: 'False' }, { value: '', label: '' }];
+
+      collectionObserver(inputArray, (updatedArray) => {
+        expect(JSON.stringify(updatedArray)).toEqual(JSON.stringify(expectation));
+        done();
+      });
+      inputArray.pop();
+    });
+
+    it('should watch for array "push" change and expect callback to be executed', (done) => {
+      const expectation = [{ value: true, label: 'True' }, { value: false, label: 'False' }, { value: '', label: '' }];
+      const inputArray: any[] = [{ value: true, label: 'True' }, { value: false, label: 'False' }];
+
+      collectionObserver(inputArray, (updatedArray) => {
+        expect(JSON.stringify(updatedArray)).toEqual(JSON.stringify(expectation));
+        done();
+      });
+      inputArray.push({ value: '', label: '' });
+    });
+
+    it('should watch for array "unshift" change and expect callback to be executed', (done) => {
+      const expectation = [{ value: '', label: '' }, { value: true, label: 'True' }, { value: false, label: 'False' }];
+      const inputArray: any[] = [{ value: true, label: 'True' }, { value: false, label: 'False' }];
+
+      collectionObserver(inputArray, (updatedArray) => {
+        expect(JSON.stringify(updatedArray)).toEqual(JSON.stringify(expectation));
+        done();
+      });
+      inputArray.unshift({ value: '', label: '' });
+    });
+
+    it('should watch for array "unshift" change and expect callback to be executed', (done) => {
+      const expectation = [{ value: true, label: 'True' }, { value: false, label: 'False' }];
+      const inputArray: any[] = [{ value: '', label: '' }, { value: true, label: 'True' }, { value: false, label: 'False' }];
+
+      collectionObserver(inputArray, (updatedArray) => {
+        expect(JSON.stringify(updatedArray)).toEqual(JSON.stringify(expectation));
+        done();
+      });
+      inputArray.shift();
+    });
+
+    it('should watch for array "unshift" change and expect callback to be executed', (done) => {
+      const expectation = [{ value: '', label: '' }, { value: false, label: 'False' }];
+      const inputArray: any[] = [{ value: '', label: '' }, { value: true, label: 'True' }, { value: false, label: 'False' }];
+
+      collectionObserver(inputArray, (updatedArray) => {
+        expect(JSON.stringify(updatedArray)).toEqual(JSON.stringify(expectation));
+        done();
+      });
+      inputArray.splice(1, 1);
+    });
+
+    it('should watch for array "reverse" change and expect callback to be executed', (done) => {
+      const expectation = [{ id: 1, value: false, label: 'False' }, { id: 2, value: true, label: 'True' }];
+      const inputArray: any[] = [{ id: 2, value: true, label: 'True' }, { id: 1, value: false, label: 'False' }];
+
+      collectionObserver(inputArray, (updatedArray) => {
+        expect(JSON.stringify(updatedArray)).toEqual(JSON.stringify(expectation));
+        done();
+      });
+      inputArray.reverse();
+    });
+
+    it('should watch for array "sort" change and expect callback to be executed', (done) => {
+      const expectation = [{ id: 1, value: false, label: 'False' }, { id: 2, value: true, label: 'True' }];
+      const inputArray: any[] = [{ id: 2, value: true, label: 'True' }, { id: 1, value: false, label: 'False' }];
+
+      collectionObserver(inputArray, (updatedArray) => {
+        expect(JSON.stringify(updatedArray)).toEqual(JSON.stringify(expectation));
+        done();
+      });
+      inputArray.sort((obj1, obj2) => obj1.id - obj2.id);
+    });
+  });
+
+  describe('propertyObserver method', () => {
+    it('should watch for an object property change and expect the callback to be executed with new value', (done) => {
+      const expectation = { hello: { firstName: 'John' } };
+      const inputObj = { hello: { firstName: '' } };
+
+      propertyObserver(inputObj.hello, 'firstName', (newValue) => {
+        expect(newValue).toEqual('John');
+        expect(inputObj).toEqual(expectation);
+        done();
+      });
+      inputObj.hello.firstName = 'John';
+    });
+  });
+});
diff --git a/packages/common/src/services/observers.ts b/packages/common/src/services/observers.ts
new file mode 100644
index 000000000..880a4e4bc
--- /dev/null
+++ b/packages/common/src/services/observers.ts
@@ -0,0 +1,39 @@
+/**
+ * Collection Observer to watch for any array changes (pop, push, reverse, shift, unshift, splice, sort)
+ * and execute the callback when any of the methods are called
+ * @param {any[]} inputArray - array you want to listen to
+ * @param {Function} callback function that will be called on any change inside array
+ */
+export function collectionObserver(inputArray: any[], callback: (outputArray: any[], newValues: any[]) => void) {
+  // Add more methods here if you want to listen to them
+  const mutationMethods = ['pop', 'push', 'reverse', 'shift', 'unshift', 'splice', 'sort'];
+
+  mutationMethods.forEach((changeMethod) => {
+    inputArray[changeMethod] = (...args: any[]) => {
+      const res = Array.prototype[changeMethod].apply(inputArray, args);  // call normal behaviour
+      callback.apply(inputArray, [inputArray, args]);  // finally call the callback supplied
+      return res;
+    };
+  });
+}
+
+/**
+ * Object Property Observer and execute the callback whenever any of the object property changes.
+ * @param {*} obj - input object
+ * @param {String} prop - object property name
+ * @param {Function} callback - function that will be called on any change inside array
+ */
+export function propertyObserver(obj: any, prop: string, callback: (newValue: any) => void) {
+  let innerValue = obj[prop];
+
+  Object.defineProperty(obj, prop, {
+    configurable: true,
+    get() {
+      return innerValue;
+    },
+    set(newValue) {
+      innerValue = newValue;
+      callback.apply(obj, [newValue, obj[prop]]);
+    }
+  });
+}
diff --git a/test/cypress/integration/example07.spec.js b/test/cypress/integration/example07.spec.js
index cd3b69826..839212bd9 100644
--- a/test/cypress/integration/example07.spec.js
+++ b/test/cypress/integration/example07.spec.js
@@ -2,7 +2,7 @@
 
 describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => {
   const GRID_ROW_HEIGHT = 45;
-  const fullTitles = ['', '', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Completed'];
+  const fullTitles = ['', '', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Completed', 'Prerequisites'];
 
   it('should display Example title', () => {
     cy.visit(`${Cypress.config('baseExampleUrl')}/example07`);
@@ -135,11 +135,11 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => {
   });
 
   it('should dynamically add 2x new "Title" columns', () => {
-    const updatedTitles = ['', '', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Completed', 'Title', 'Title'];
+    const updatedTitles = ['', '', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Completed', 'Prerequisites', 'Title', 'Title'];
 
     cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(2)`).should('contain', 'Task 0');
-    cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(8)`).should('not.exist');
     cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(9)`).should('not.exist');
+    cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(10)`).should('not.exist');
 
     cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(2)`)
       .should('contain', 'Task 0')
@@ -155,12 +155,12 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => {
       .each(($child, index) => expect($child.text()).to.eq(updatedTitles[index]));
 
     cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(2)`).should('contain', 'Task 0');
-    cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(8)`).should('contain', 'Task 0');
     cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(9)`).should('contain', 'Task 0');
+    cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(10)`).should('contain', 'Task 0');
   });
 
   it('should dynamically remove 1x of the new "Title" columns', () => {
-    const updatedTitles = ['', '', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Completed', 'Title'];
+    const updatedTitles = ['', '', 'Title', 'Duration', '% Complete', 'Start', 'Finish', 'Completed', 'Prerequisites', 'Title'];
 
     cy.get('[data-test=remove-title-column-btn]')
       .click();
@@ -195,11 +195,11 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => {
     cy.get('.flatpickr-calendar:visible .flatpickr-day').contains('22').click('bottom', { force: true });
     cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(6)`).should('contain', '2009-01-22');
 
-    cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(8)`).should('contain', 'Task 0000');
+    cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(9)`).should('contain', 'Task 0000');
   });
 
   it('should move "Duration" column to a different position in the grid', () => {
-    const expectedTitles = ['', '', 'Title', '% Complete', 'Start', 'Finish', 'Duration', 'Completed', 'Title'];
+    const expectedTitles = ['', '', 'Title', '% Complete', 'Start', 'Finish', 'Duration', 'Completed', 'Prerequisites', 'Title'];
 
     cy.get('.slick-header-columns')
       .children('.slick-header-column:nth(3)')
@@ -219,7 +219,7 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => {
   });
 
   it('should be able to hide "Duration" column', () => {
-    const expectedTitles = ['', '', 'Title', '% Complete', 'Start', 'Finish', 'Completed', 'Title'];
+    const expectedTitles = ['', '', 'Title', '% Complete', 'Start', 'Finish', 'Completed', 'Prerequisites', 'Title'];
 
     cy.get('[data-test="hide-duration-btn"]').click();
 
@@ -230,7 +230,7 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => {
   });
 
   it('should be able to click disable Filters functionality button and expect no Filters', () => {
-    const expectedTitles = ['', '', 'Title', '% Complete', 'Start', 'Finish', 'Completed', 'Title'];
+    const expectedTitles = ['', '', 'Title', '% Complete', 'Start', 'Finish', 'Completed', 'Prerequisites', 'Title'];
 
     cy.get('[data-test="disable-filters-btn"]').click().click(); // even clicking twice should have same result
 
@@ -267,7 +267,7 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => {
   });
 
   it('should be able to toggle Filters functionality', () => {
-    const expectedTitles = ['', '', 'Title', '% Complete', 'Start', 'Finish', 'Completed', 'Title'];
+    const expectedTitles = ['', '', 'Title', '% Complete', 'Start', 'Finish', 'Completed', 'Prerequisites', 'Title'];
 
     cy.get('[data-test="toggle-filtering-btn"]').click(); // hide it
 
@@ -280,7 +280,7 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => {
       .each(($child, index) => expect($child.text()).to.eq(expectedTitles[index]));
 
     cy.get('[data-test="toggle-filtering-btn"]').click(); // show it
-    cy.get('.slick-headerrow-columns .slick-headerrow-column').should('have.length', 8);
+    cy.get('.slick-headerrow-columns .slick-headerrow-column').should('have.length', 9);
 
     cy.get('.grid7')
       .find('.slick-header-columns')
@@ -451,7 +451,7 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => {
 
   it('should open Column Picker and show the "Duration" column back to visible and expect it to have kept its position after toggling filter/sorting', () => {
     // first 2 cols are hidden but they do count as li item
-    const expectedFullPickerTitles = ['', '', 'Title', '% Complete', 'Start', 'Finish', 'Duration', 'Completed', 'Title'];
+    const expectedFullPickerTitles = ['', '', 'Title', '% Complete', 'Start', 'Finish', 'Duration', 'Completed', 'Prerequisites', 'Title'];
 
     cy.get('.grid7')
       .find('.slick-header-column')
@@ -491,4 +491,70 @@ describe('Example 07 - Row Move & Checkbox Selector Selector Plugins', () => {
         }
       });
   });
+
+  it('should click Add Item button 2x times and expect "Task 500" and "Task 501" to be created', () => {
+    cy.get('[data-test="add-item-btn"]').click();
+    cy.wait(200);
+    cy.get('[data-test="add-item-btn"]').click();
+
+    cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(2)`).should('contain', 'Task 501');
+    cy.get(`[style="top:${GRID_ROW_HEIGHT * 1}px"] > .slick-cell:nth(2)`).should('contain', 'Task 500');
+
+    cy.get('[data-test="toggle-filtering-btn"]').click(); // show it back
+  });
+
+  it('should open the "Prerequisites" Filter and expect to have Task 500 & 501 in the Filter', () => {
+    cy.get('div.ms-filter.filter-prerequisites')
+      .trigger('click');
+
+    cy.get('.ms-drop')
+      .find('span:nth(1)')
+      .contains('Task 501');
+
+    cy.get('.ms-drop')
+      .find('span:nth(2)')
+      .contains('Task 500');
+
+    cy.get('div.ms-filter.filter-prerequisites')
+      .trigger('click');
+  });
+
+  it('should open the "Prerequisites" Editor and expect to have Task 500 & 501 in the Editor', () => {
+    cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(8)`)
+      .should('contain', '')
+      .click();
+
+    cy.get('.ms-drop')
+      .find('span:nth(1)')
+      .contains('Task 501');
+
+    cy.get('.ms-drop')
+      .find('span:nth(2)')
+      .contains('Task 500');
+
+    cy.get('[name=editor-prerequisites].ms-drop ul > li:nth(0)')
+      .click();
+
+    cy.get('.ms-ok-button')
+      .last()
+      .click({ force: true });
+
+    cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(8)`).should('contain', 'Task 501');
+  });
+
+  it('should delete the last item "Task 501" and expect it to be removed from the Filter', () => {
+    cy.get('[data-test="delete-item-btn"]').click();
+
+    cy.get(`[style="top:${GRID_ROW_HEIGHT * 0}px"] > .slick-cell:nth(2)`).should('contain', 'Task 500');
+
+    cy.get('div.ms-filter.filter-prerequisites')
+      .trigger('click');
+
+    cy.get('.ms-drop')
+      .find('span:nth(1)')
+      .contains('Task 500');
+
+    cy.get('div.ms-filter.filter-prerequisites')
+      .trigger('click');
+  });
 });