fix: infinite digest loop with ngRepeat + ImmutableJS (#514)

The addition of `ImmutableJS` caused some issues with Angular's digest
loop. Since `Immutable#toJS()` returns a new object/array every time
(that is, different references), it caused AngularJS to get stuck in an
infinite digest loop when using `ngRepeat` over a function that called
`Immutable#toJS()`.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This commit is contained in:
Juan Cruz Viotti 2016-06-23 11:41:24 -04:00 committed by GitHub
parent 2b9f0b5003
commit 77f2b1d1cc
2 changed files with 25 additions and 3 deletions

View File

@ -5,7 +5,7 @@
<div class="component-drive-selector-body modal-body">
<ul class="list-group">
<li class="list-group-item" ng-repeat="drive in modal.drives.getDrives()"
<li class="list-group-item" ng-repeat="drive in modal.drives.getDrives() track by drive.device"
ng-disabled="!modal.state.isDriveValid(drive)"
ng-click="modal.state.isDriveValid(drive) && modal.state.toggleSetDrive(drive)">
<div>

View File

@ -65,6 +65,28 @@ Drives.service('DrivesModel', function() {
});
};
// This workaround is needed to avoid AngularJS from getting
// caught in an infinite digest loop when using `ngRepeat`
// over a function that returns a mutable version of an
// ImmutableJS object.
//
// The problem is that everytime you call `myImmutableObject.toJS()`
// you will get a new object, whose reference is different from
// the one you previously got, even if the data is exactly the same.
const memoizeImmutableListReference = function(func) {
let previous = [];
return function() {
const list = func.apply(this, arguments);
if (!_.isEqual(list, previous)) {
previous = list;
}
return previous;
};
};
/**
* @summary Get detected drives
* @function
@ -75,9 +97,9 @@ Drives.service('DrivesModel', function() {
* @example
* const drives = DrivesModel.getDrives();
*/
this.getDrives = function() {
this.getDrives = memoizeImmutableListReference(function() {
return store.getState().toJS().availableDrives;
};
});
});