The SelectionModel is implemented as a part of @angular/cdk library. The documentation can be found in the Collections page from Angular Material Documentation.
In the code we use the following import:
import { SelectionModel } from '@angular/cdk/collections';
The SelectionModel is build using the native JavascriptSet() object, as can be found in the source code:
private _selection = new Set<T>();
The Set object lets you store unique values of any type, whether primitive values or object references.
What we need to consider first is that, in Javascript, two different instances of objects are always not equal:
const obj1 = { a: 1, b: 2 };
const obj2 = { a: 1, b: 2 };
obj1 !== obj2; // => true
So, the following situation will arive:
const mySet1 = new Set();
const obj1 = {a: 1, b: 2};
mySet1.add(obj1);
const obj2 = {a: 1, b: 2};
mySet1.add(obj2) // obj2 is referencing a different object, so the object will be added in the set
More info about JS Set() here.
Now, what we really need is a deep value equality check between the objects in our set. Unfortunatelly, there is no method to override the comparison method in the Set object, so I've wrote my own implementation of the SelectionModel - SelectionModelImmutableJS by using the very popular library called immutable-js. The implementation was inspired by the following answer.
To simplify, by using immutable-js, we'll have the following situation:
const { Map, Set } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = Map({ a: 1, b: 2, c: 3 });
map1 !== map2; // => true, two different instances are not reference-equal
map1.equals(map2); // true, but are value-equal if they have the same values
const set = Set().add(map1);
set.has(map2); // true, because these are value-equal
The code for the Selection Model is a little bit too large and I will not post it inline - it can be found in the working demo.
In the app we'll use:
import { SelectionModelImmutableJS } from './selection-model-immutable';
.....
public selection = new SelectionModelImmutableJS<IPeriodicElement>(
true,
this.initialSelection
);
The full working demo:
https://stackblitz.com/edit/angular-ivy-wnvohl