Selected property filter Ember.js hasMany array

I am trying to filter the content of the hasber field "ember-data" hasMany. My model has some sub-queries that I want to filter on the childOptions property on my controller and display in the template using

{{#each childOptions}}stuff{{/each}}

      

When I put this on my controller, it works, and each iterates over the corresponding values:

childOptions: Ember.computed.filterBy('model.subquestions', 'surveyQuestionType.name', 'childOption'),

      

However, when I do this, nothing is displayed.

childOptions: Ember.computed.filter('model.subquestions', function(subquestion) {
    return subquestion.get('surveyQuestionType.name') === 'childOption';
}),

      

'surveyQuestionType' is a DS.belongsTo that exists in the model for "subsequences" and has a "name" property.

I want to understand why the filterBy method works while the "filter" method (so I can use the "filter" for more complex queries in the future). I think it has something to do with promises and the syntax subquestion.get('property')

I use inside the filter function.

EDIT:

This is the model:

App.SurveyQuestion = DS.Model.extend(Ember.Validations.Mixin, {
    surveyQuestionType: DS.belongsTo('surveyQuestionType', { async: true }),
    display: DS.belongsTo('surveyQuestionDisplay', { async: true, inverse: 'surveyQuestion' }),
    sortOrder: DS.attr('number'),
    parent: DS.belongsTo('surveyQuestion', { async: true, inverse: 'subquestions' }),
    parentDependencyCriteria: DS.attr('string'),
    required: DS.attr('boolean'),
    surveySections: DS.hasMany('surveySectionQuestion', { async: true, inverse: 'surveyQuestion' }),
    subquestions: DS.hasMany('surveyQuestion', { async: true, inverse: 'parent' })
});

      

+3


source to share


2 answers


As of ember-data 1.0.0-beta.11, promises seem to work more smoothly and I had success with this (I did go with a different approach to my original problem, but used this code in a similar situation):

childOptions: function() {
    var subquestions = this.get('subquestions');
    if (subquestions) {
        return subquestions.filter(function(subquestion) {    
            var surveyQuestion = subquestion.get('surveyQuestion');
            return (surveyQuestion && surveyQuestion.get('name') === 'childOptions');
        });
    }
}.property('subquestions.@each.surveyQuestion')

      



.property('subquestions.@each.surveyQuestion')

forces the property to update when promised surveyQuestion

. If you put some output, you can see that initially the property is called and subquestions

will be null.

+2


source


I've spent more time discovering this category of problems with my own work than I'd like to admit, but luckily the solution is simple. In the definition DS.Model

there is a relation surveyQuestionType

a belongsTo

with {async: true}

? If so, then your problem.

Whenever you establish a relationship in DS.Model

how {async: true}

, you can think of it as the actual definition of the promise that you will end up with that property. It makes sense and becomes intuitive, but it's not very well documented!

Promises are especially tricky for newbies because your Handlebars template will transparently handle {{surveyQuestionType.name}}

whether it's a surveyQuestionType

specific value or a promise. This is confusing for newbies because you can't tell at first blush if Handlebars is displaying a specific meaning or promise.

When you are dealing with a promise, you can directly access what is allowed in that property content

. In fact, you can even set this property content

. But be careful with this, because reading / writing directly to the property content

does not affect any pending operations that might be promised. Therefore, if the promise is still pending when you write its value content

, your record will be overwritten once it is resolved.

I am writing directly to the property content

when I add a new object and have to fill the promise relationship. It makes sense, but if I was reading the value, I would need to find a way to guarantee myself that the promise was already resolved when I read the property content

... or I could let Handlebars handle it directly, knowing that for pure display logic I don't need 150ms latency.

Anyway, if all of the above applies to your problem, here's how you can edit your code to make this work:



childOptions: Ember.computed.filter('model.subquestions', function(subquestion) {
    return subquestion.get('surveyQuestionType.content.name') === 'childOption';
})

      

UPDATE # 1: I believe I just violated my own recommendation without thinking, without resorting to content

. See my comments for debugging information and you can also try this:

childOptions: Ember.computed.filter('model.subquestions', function(subquestion) {
    return subquestion.get('surveyQuestionType').then( function( model ) {
       return model.get('name') === 'childOption';
    });
})

      

UPDATE # 2: See my comments below and in particular https://github.com/emberjs/data/issues/1865 . this turned out to be a more complex issue and I would like to welcome input from others to clarify the best approach here.

I solved this problem in my own code by processing promises upstream so that I can access the property directly, content

or not deal with promises at all in my filters.

+5


source







All Articles