Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ability to easily filter the results of findDescendantModels #2058

Closed
moloko opened this issue Apr 30, 2018 · 9 comments
Closed

add ability to easily filter the results of findDescendantModels #2058

moloko opened this issue Apr 30, 2018 · 9 comments
Assignees

Comments

@moloko
Copy link
Contributor

moloko commented Apr 30, 2018

With adaptModel.findDescendants, if you wanted to do something like get all available, mandatory components for a contentObject, you could do this:

Adapt.findById('co-05').findDescendants('components').where({'_isAvailable': true, '_isOptional': false});

However, following #1616 this function is deprecated in favour of findDescendantModels - but as this function returns an Array rather than a Backbone Collection it's necessary to do the following to achieve the same result:

_.filter(Adapt.findById('co-05').findDescendantModels('components'), function(comp) {
    return comp.get('_isAvailable') === true && comp.get('_isOptional') === false;
});

Which is obviously quite a bit wordier compared to the original.

I think it would therefore be useful to amend findDescendantModels to have an optional 2nd parameter filterBy that would give us similar functionality to the original version.

@moloko moloko self-assigned this Apr 30, 2018
@moloko
Copy link
Contributor Author

moloko commented Apr 30, 2018

OK I'm obviously being a bit thick here and completely failing to realise that you could just do:

_.where(Adapt.findById('co-05').findDescendantModels('components'), {'_isAvailable': true, '_isOptional': false});

I blame the code in PLP's completionCalculations.js which uses _.filter even though you could achieve the same result in less code by using _.where...!

However, still might be useful to include this 2nd parameter in the function anyway just to make it even easier? i.e.

Adapt.findById('co-05').findDescendantModels('components', {'_isAvailable': true, '_isOptional': false});

@oliverfoster
Copy link
Member

oliverfoster commented Apr 30, 2018

You can't do the _.where because findDescendantModels returns an array of models. You were right first time. Not being stoopid. _.where works on an array of objects.

@moloko
Copy link
Contributor Author

moloko commented Apr 30, 2018

ah of course it does! phew...

@oliverfoster
Copy link
Member

You might find http://underscorejs.org/#isMatch useful for comparing the options.filterBy = { name: value } to the model.toJSON()

if (options && options.filterBy) {
  return _.filter(models, function(model) {
     return _.isMatch(model.toJSON(), options.filterBy);
  });
}

@moloko
Copy link
Contributor Author

moloko commented Apr 30, 2018

Oh that's interesting, I'll give that a try - definitely shorter than what I have at the moment:

return _.filter(returnedDescendants, function(descendant){
    for (var property in filterBy) {
        var value = filterBy[property];
        if (descendant.get(property) !== value) {
            return false;
        }
    }
    return true;
});

@oliverfoster
Copy link
Member

It might also be slower than what you have.

@oliverfoster
Copy link
Member

oliverfoster commented Apr 30, 2018

Oh, I keep meaning to say, if you make the second parameter an object with sub attributes, it leaves space for future behavioural extensions (like sortBy).

Adapt.findById('co-10').findDescendantModels('component', { filterBy: { _component: 'hotgraphic' } });

Adapt.findById('co-10').findDescendantModels('component', { 
  filterBy: { 
    _component: 'hotgraphic' 
  } 
});

It can also make it read more clearly despite being a bit odd syntactically.

@moloko
Copy link
Contributor Author

moloko commented Apr 30, 2018

It might also be slower than what you have.

It does seem to be... not the best test in the world but filtering the 30 components in OOTB Adapt using the _.isMatch method mostly seems to take around 1 - 3ms depending on browser whereas using a for...in loop is always < 0.5ms

I'll try and find some time to test against a larger amount of content tomorrow.

@moloko
Copy link
Contributor Author

moloko commented May 4, 2018

so, in a course with 75 components, using _.isMatch is anything from 1 x to 3 times slower in Firefox and 1x to 4x slower in IE11 - so I'm going to stick with the for..in version as although _.isMatch is a few lines shorter I don't think it's that much more readable (kind of depends on your familiarity with the _.isMatch function I guess...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants