Skip to content

Commit

Permalink
docs(mvc.Collection): add docs and testing for updated collection met… (
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesgeorgewilliams authored Jan 12, 2024
1 parent bffa2c0 commit 0e6d464
Show file tree
Hide file tree
Showing 12 changed files with 163 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<pre class="docs-method-signature"><code>collection.each(fn, [context])</code></pre>

<p>
Iterate over models of a collection, and invoke <code>fn</code> for each model. <code>fn</code> is invoked with 3 arguments:
<i>(model, index, array)</i>.
</p>

<pre><code>const a = new mvc.Model({ id: 1, label: 'a' });
const b = new mvc.Model({ id: 2, label: 'b' });
const c = new mvc.Model({ id: 3, label: 'c' });
const col = new mvc.Collection([a, b, c]);

col.each((model, i) => model.set({ customData: i }));

col.each((model) => console.log(model.get('customData')));
// 0
// 1
// 2
</code></pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<pre class="docs-method-signature"><code>collection.filter(fn, [context])</code></pre>

<p>
Iterate over models of a collection, returning an array of all models <code>fn</code> returns truthy for. <code>fn</code> is invoked with three
arguments: <i>(model, index, array)</i>.
</p>

<pre><code>const a = new mvc.Model({ id: 3, label: 'a' });
const b = new mvc.Model({ id: 2, label: 'b' });
const c = new mvc.Model({ id: 1, label: 'c' });
const d = new mvc.Model({ id: 0, label: 'd' });
const col = new mvc.Collection([a, b, c, d]);

console.log(col.filter((model) => model.get('id') === 0).length); // 1
</code></pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<pre class="docs-method-signature"><code>collection.first()</code></pre>

<p>
Return the first model of a collection.
</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<pre class="docs-method-signature"><code>collection.includes(value)</code></pre>

<p>
Return <code>true</code> if model is found in a collection.
</p>

<pre><code>const a = new mvc.Model({ id: 3, label: 'a' });
const b = new mvc.Model({ id: 2, label: 'b' });
const c = new mvc.Model({ id: 1, label: 'c' });
const d = new mvc.Model({ id: 0, label: 'd' });
const col = new mvc.Collection([a, b, c]);

console.log(col.includes(a)); // true
console.log(col.includes(d)); // false
</code></pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<pre class="docs-method-signature"><code>collection.isEmpty()</code></pre>

<p>
Return <code>true</code> if a collection is empty.
</p>

<pre><code>const col = new mvc.Collection([]);

console.log(col.isEmpty()); // true

col.set([new mvc.Model({ id: 1, label: 'a' })]);

console.log(col.isEmpty()); // false
</code></pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<pre class="docs-method-signature"><code>collection.last()</code></pre>

<p>
Return the last model of a collection.
</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<pre class="docs-method-signature"><code>collection.map(fn, [context])</code></pre>

<p>
Create an array of values by running each model in the collection through <code>fn</code>. <code>fn</code> is invoked with three arguments:
<i>(model, index, array)</i>.
</p>

<pre><code>const a = new mvc.Model({ id: 3, label: 'a' });
const b = new mvc.Model({ id: 2, label: 'b' });
const c = new mvc.Model({ id: 1, label: 'c' });
const d = new mvc.Model({ id: 0, label: 'd' });
const col = new mvc.Collection([a, b, c, d]);

console.log(col.map((model) => model.get('label')).join(' ')); // 'a b c d'
</code></pre>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<pre class="docs-method-signature"><code>collection.reduce(fn, [initialValue])</code></pre>

<p>
Reduce a collection to a value which is the accumulated result of running each model in the collection through <code>fn</code>, where each
successive invocation is supplied the return value of the previous. If <code>initialValue</code> is not given, the first model in the collection
is used as the initial value. <code>fn</code> is invoked with four arguments: <i>(accumulator, currentValue, currentIndex, array)</i>.
</p>

<pre><code>const collection = new mvc.Collection([new mvc.Model({ id: 1, label: 'a' })]);

console.log(collection.reduce((acc, model) => acc.get('id') + model.id )); // 2
</code></pre>
4 changes: 2 additions & 2 deletions packages/joint-core/src/mvc/Collection.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,8 @@ assign(Collection.prototype, Events, {
},

// Runs "reducer" fn over all elements in the collection, in ascending-index order, and accumulates them into a single value
reduce: function(fn, initAcc, context) {
return this.models.reduce(fn, initAcc, context);
reduce: function(fn, initAcc = this.first()) {
return this.models.reduce(fn, initAcc);
},

// Private method to reset all internal state. Called when the collection
Expand Down
60 changes: 60 additions & 0 deletions packages/joint-core/test/jointjs/mvc.collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,66 @@ QUnit.module('joint.mvc.Collection', function(hooks) {
assert.equal(JSON.stringify(col), '[{"id":3,"label":"a"},{"id":2,"label":"b"},{"id":1,"label":"c"},{"id":0,"label":"d"}]');
});

QUnit.test('Collection methods', function(assert) {
assert.expect(14);

// each
col.each((model, i) => model.set({ customData: i }));
assert.equal(JSON.stringify(col), '[{"id":3,"label":"a","customData":0},{"id":2,"label":"b","customData":1},{"id":1,"label":"c","customData":2},{"id":0,"label":"d","customData":3}]');

// filter
assert.equal(col.filter((model) => model.get('customData') === 0).length, 1);

// first
assert.equal(col.first().get('id'), col.models[0].id);

// includes
assert.ok(col.includes(col.models[0]));

const model = new joint.mvc.Model({ id: 5, label: 'a' });
assert.ok(!col.includes(model));

// last
assert.equal(col.last().get('id'), col.models[col.models.length - 1].id);

// isEmpty
assert.ok(!col.isEmpty());

const collection = new joint.mvc.Collection([]);
assert.ok(collection.isEmpty());

collection.set([new joint.mvc.Model({ id: 1, label: 'a' })]);
assert.ok(!collection.isEmpty());

// map
assert.equal(col.map((model) => model.get('label')).join(' '), 'a b c d');

// reduce
const initAcc = 0;
assert.equal(col.reduce((acc, model) => acc + model.id, initAcc), 6);
assert.equal(collection.reduce((acc, model) => acc.get('id') + model.id ), 2);

// sortBy
assert.deepEqual(col.sortBy((model) => model.id)[0], col.at(3));

// toArray
assert.ok(Array.isArray(col.toArray()));
});

QUnit.test('Collection methods with object-style and property-style iteratee', function(assert) {
assert.expect(2);
const model = new joint.mvc.Model({ a: 4, b: 1, e: 3 });
const collection = new joint.mvc.Collection([
{ a: 1, b: 1 },
{ a: 2, b: 1, c: 1 },
{ a: 3, b: 1 },
model
]);

assert.deepEqual(collection.sortBy('a')[3], model);
assert.deepEqual(collection.sortBy('e')[0], model);
});

QUnit.test('reset', function(assert) {
assert.expect(16);

Expand Down
2 changes: 1 addition & 1 deletion packages/joint-core/types/joint.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3153,7 +3153,7 @@ export namespace mvc {
isEmpty(): boolean;
last(): TModel;
map<TResult>(iterator: ListIterator<TModel, TResult>, context?: any): TResult[];
reduce<TResult>(iterator: MemoIterator<TModel, TResult>, memo?: TResult, context?: any): TResult;
reduce<TResult>(iterator: MemoIterator<TModel, TResult>, memo?: TResult): TResult;
sortBy(iterator?: ListIterator<TModel, any>, context?: any): TModel[];
sortBy(iterator: string, context?: any): TModel[];
toArray(): TModel[];
Expand Down

0 comments on commit 0e6d464

Please sign in to comment.