0

I have following computed properties, tempate and a model where there are relationships which are async=true

ArrayController is used to sort the people-cards 1st after upgrading to 2.1.8 its not working. how to achieve this ?

computed properties

 people: computed(
    'model.coordinators',
    'model.directors',
    'model.professors',
    'model.students',
    'model.advisors',
    'model.managers',
    'model.contacts',
    'model.consultants',
    'model.guests',


    function() {

      console.log("people......")

      var coordinators = this.get( 'model.coordinators' ),
          professors   = this.get( 'model.professors' ),
          guests       = this.get( 'model.guests' ),
          students     = this.get( 'model.students' ),
          advisors     = this.get( 'model.advisors' ),
          directors    = this.get( 'model.directors' ),
          consultants  = this.get( 'model.consultants' ),
          contacts     = this.get( 'model.contacts' ),
          managers     = this.get( 'model.managers' ),
          people       = A();

      coordinators.forEach( function( person ) {

        people.pushObject( EmberObject.create( { person:person, id:person.id, role:'coordinators', title:'Coordinator', selected:false } ) );
      } );

      professors.forEach( function( person ) {

        people.pushObject( EmberObject.create( { person:person, id:person.id, role:'professors', title:'Faculty', selected:false } ) );
      } );

      guests.forEach( function( person ) {

        people.pushObject( EmberObject.create( { person:person, id:person.id, role:'guests', title:'Guest', selected:false } ) );
      } );

      students.forEach( function( person ) {

        people.pushObject( EmberObject.create( { person:person, id:person.id, role:'students', title:'Participant', selected:false } ) );
      } );

      advisors.forEach( function( person ) {

        people.pushObject( EmberObject.create( { person:person, id:person.id, role:'advisors', title:'Programme Advisor', selected:false } ) );
      } );

      directors.forEach( function( person ) {

        people.pushObject( EmberObject.create( { person:person, id:person.id, role:'directors', title:'Programme Director', selected:false } ) );
      } );

      consultants.forEach( function( person ) {

        people.pushObject( EmberObject.create( { person:person, id:person.id, role:'consultants', title:'Programme Consultant', selected:false } ) );
      } );

      contacts.forEach( function( person ) {

        people.pushObject( EmberObject.create( { person:person, id:person.id, role:'contacts', title:'Programme Contact', selected:false } ) );
      } );

      managers.forEach( function( person ) {

        people.pushObject( EmberObject.create( { person:person, id:person.id, role:'managers', title:'Programme Management', selected:false } ) );
      } );

    return people;
  } ),
  peopleWithoutDuplicates: computed( 'people' ,function() {

    var dedupedPeople = {},
        people = this.get( 'people' );

    people.forEach( person => dedupedPeople[ person.id ] = person );

    return Object.keys( dedupedPeople ).map( id => dedupedPeople[ id ] );
  } ),

  groupedPeople: computed( 'peopleWithoutDuplicates', 'filter', function() {

    var people    = this.get( 'peopleWithoutDuplicates' ),
        tabPeople = A(),
        getFilter = this.get( 'filter' ),
        arrayController;

    if ( getFilter === 0 || getFilter === 1 ) {

      tabPeople.pushObjects( people.filterBy( 'role', 'coordinators' ) );
      tabPeople.pushObjects( people.filterBy( 'role', 'directors' ) );
      tabPeople.pushObjects( people.filterBy( 'role', 'professors' ) );
      tabPeople.pushObjects( people.filterBy( 'role', 'advisors' ) );
      tabPeople.pushObjects( people.filterBy( 'role', 'managers' ) );
      tabPeople.pushObjects( people.filterBy( 'role', 'contacts' ) );
      tabPeople.pushObjects( people.filterBy( 'role', 'consultants' ) );
      tabPeople.pushObjects( people.filterBy( 'role', 'guests' ) );
    }

    if ( getFilter === 0 || getFilter === 2 ) {

      tabPeople.pushObjects( people.filterBy( 'role', 'students' ) );
    }

    arrayController = Ember.Controller.create( {

   model: tabPeople,
   sortProperties: [ 'person.lastName' ],
   sortAscending: true
    } );

return arrayController
  } ),





  filteredResults: computed( 'filterText', 'groupedPeople.[]', function() {

    var filter = this.get( 'filterText' ).replace( /\s+([^\s]+)/, '|$1').replace( /\s+$/, '' ),

        regExp = new RegExp( filter, 'i' ),
        filteredResults = this.get('groupedPeople').filter(function(result) 
        {
          return regExp.test( result.get( 'person.fullName' ) );
        } );

    return filteredResults;
  } ),

updated code with the help of @lux and its still not working

export default Mixin.create( {
  animate: true,
  filterText: '',
  filter: 0,
  filterTabs: A(),
  card: null,
  changeofperson:null,
  people:A(),

  people: computed(
    'model.coordinators.[]',
    'model.directors.[]',
    'model.professors.[]',
    'model.students.[]',
    'model.advisors.[]',
    'model.managers.[]',
    'model.contacts.[]',
    'model.consultants.[]',
    'model.guests.[]',

    function() {
      debugger;
      var people = A();
      this.get( 'model.coordinators.[]' ).forEach( function( person ) {

        people.pushObject( Ember.Object.create( { person:person, id:person.id, role:'coordinators', title:'Coordinator', selected:false } ) );
      } );

      this.get( 'model.professors.[]' ).forEach( function( person ) {

        people.pushObject( Ember.Object.create( { person:person, id:person.id, role:'professors', title:'Faculty', selected:false } ) );
      } );

      this.get( 'model.guests.[]' ).forEach( function( person ) {

        people.pushObject( Ember.Object.create( { person:person, id:person.id, role:'guests', title:'Guest', selected:false } ) );
      } );

      this.get( 'model.students.[]' ).forEach( function( person ) {

        people.pushObject( Ember.Object.create( { person:person, id:person.id, role:'students', title:'Participant', selected:false } ) );
      } );

      this.get( 'model.advisors.[]' ).forEach( function( person ) {

        people.pushObject( Ember.Object.create( { person:person, id:person.id, role:'advisors', title:'Programme Advisor', selected:false } ) );
      } );

      this.get( 'model.directors.[]' ).forEach( function( person ) {

        people.pushObject( Ember.Object.create( { person:person, id:person.id, role:'directors', title:'Programme Director', selected:false } ) );
      } );

      this.get( 'model.consultants.[]' ).forEach( function( person ) {

        people.pushObject( Ember.Object.create( { person:person, id:person.id, role:'consultants', title:'Programme Consultant', selected:false } ) );
      } );

      this.get( 'model.contacts.[]' ).forEach( function( person ) {

        people.pushObject( Ember.Object.create( { person:person, id:person.id, role:'contacts', title:'Programme Contact', selected:false } ) );
      } );

      this.get( 'model.managers.[]' ).forEach( function( person ) {

        people.pushObject( Ember.Object.create( { person:person, id:person.id, role:'managers', title:'Programme Management', selected:false } ) );
      } );

      return people;

    }),


    sortedPeople: computed('people', function() {
      debugger;
      return this.get('people').sortBy('person.lastName')
    }),

    peopleWithoutDuplicates: computed( 'sortedPeople' ,function() {

      var dedupedPeople = {},
      people = this.get( 'people' );

      people.forEach( person => dedupedPeople[ person.id ] = person );

      return Object.keys( dedupedPeople ).map( id => dedupedPeople[ id ] );
    } ),

      groupedPeople: computed( 'peopleWithoutDuplicates', 'filter', function() {

        var people    = this.get( 'peopleWithoutDuplicates' ),
        tabPeople = A(),
        getFilter = this.get( 'filter' ),
        arrayController;

        if ( getFilter === 0 || getFilter === 1 ) {

          tabPeople.pushObjects( people.filterBy( 'role', 'coordinators' ) );
          tabPeople.pushObjects( people.filterBy( 'role', 'directors' ) );
          tabPeople.pushObjects( people.filterBy( 'role', 'professors' ) );
          tabPeople.pushObjects( people.filterBy( 'role', 'advisors' ) );
          tabPeople.pushObjects( people.filterBy( 'role', 'managers' ) );
          tabPeople.pushObjects( people.filterBy( 'role', 'contacts' ) );
          tabPeople.pushObjects( people.filterBy( 'role', 'consultants' ) );
          tabPeople.pushObjects( people.filterBy( 'role', 'guests' ) );
        }

        if ( getFilter === 0 || getFilter === 2 ) {

          tabPeople.pushObjects( people.filterBy( 'role', 'students' ) );
        }

        // arrayController = Ember.Controller.create( {
        //
        //   model: tabPeople,
        //   sortProperties: [ 'person.lastName' ],
        //   sortAscending: true
        // } );

        return tabPeople;
      } ),

      filteredResults: computed( 'filterText', 'groupedPeople.[]', function() {

        var sortedArr =this.get('groupedPeople')
        var filter = this.get( 'filterText' ).replace( /\s+([^\s]+)/, '|$1' ).replace( /\s+$/, '' ),
        regExp = new RegExp( filter, 'i' ),

        filteredResults = sortedArr.filter( function( result ) {
          return regExp.test( result.get( 'person.fullName' ) );
        } );

        return filteredResults;
      } ),

      person: Ember.computed( 'card.person', function() {

        return this.get( 'card.person' );
      } ),


    } ); 

template.hbs

{{#each filteredResults as |result|}}
    <div class="grid--column grid--column-3">

      {{people-card card=result loaded=result.person.isLoaded openProfileAction="openProfile" profileLoadedAction="personLoaded" }}

    </div>
  {{/each}}

model

{
    coordinators: DS.hasMany( 'profile', { async: true } ),
    directors: DS.hasMany( 'profile', { async: true } ),
    professors: DS.hasMany( 'profile', { async: true } ),
    students: DS.hasMany( 'profile', { async: true } ),
    advisors: DS.hasMany( 'profile', { async: true } ),
}

im trying to show a sorted list of people-cards in template ( sort by lastname ) . this works under ember 1.13 but when i upgraded to ember2.1.8 im getting an error ArrayController is depreciated. how to achive the sorting for those async=true relationships to work this again ?

  • what exactly is your question? What about your code does not work? And why not just use [`sortBy`](https://emberjs.com/api/ember/3.5/classes/EmberArray/methods/sortBy?anchor=sortBy)? – Lux Oct 16 '18 at 20:49
  • Hi @Lux thanks for the replying. sortby cannot use cause only the child component is getting data from those async calls. so since i want to sort it by profile.lastName , i cannot get that data. ( cause data is not available ) – Thilina Dinith Fonseka Oct 17 '18 at 01:58
  • tabPeople.sortBy() will not work in here :( – Thilina Dinith Fonseka Oct 17 '18 at 01:58
  • Then call sortby in that child component – Lux Oct 17 '18 at 01:59
  • simple i need to replace ArrayController with a sorted array by person.lastName which is belongs to async=true relationship – Thilina Dinith Fonseka Oct 17 '18 at 01:59
  • This looks like a x/y problem. Please edit the question and explain what you want to have from a user perspective – Lux Oct 17 '18 at 02:00
  • @Lux i have modified the question again with more details – Thilina Dinith Fonseka Oct 17 '18 at 02:46
  • You should consider rewriting this using computed macros. E.g. your `people` computed property is very complex but you should be able to replace it by a one-liner using [`union` macro](https://www.emberjs.com/api/ember/3.5/functions/@ember%2Fobject%2Fcomputed/union). Same for `peopleWithoutDuplicates` which seems to achieve the same as [`uniq` macro](https://www.emberjs.com/api/ember/3.5/functions/@ember%2Fobject%2Fcomputed/uniq). [`ember-awesome-macros`](https://github.com/kellyselden/ember-awesome-macros) provides a `groupBy` macro. – jelhan Oct 17 '18 at 08:15
  • @jelhan thanks for the comment. but the issue is not cause of those computed property. issue comes with the relationships that are in the model with async=true. since im trying to sort by a value which is not there and which is async=true it is not sorting. when i used arraycontroller in ember 1.13 it works because it maps the relationships accordingly and sort. – Thilina Dinith Fonseka Oct 18 '18 at 05:49

2 Answers2

0

Actually I don't really understand why your current code works. Because if it does it will also work with sortBy.

The problem you're mentioning with async relationship is true. However AFAIK your current code should not work as well because the dependency keys of people is wrong.

Basically you have two ways to solve your problem:

  1. by using the promises and returning a PromiseArray
  2. by utilising computed properties

There is additionally ember-computed-promise which I've written to address similar issues. It's more an experiment tho.

So for utilising computed properties you first have to fix the dependency key of your people computed property. It could then look like this:

people: computed(
  'model.coordinators.[]',
  'model.directors.[]',
  ...
  function() {
    [
      'coordinators',
      'directors',
      ...
    ].forEach(n => this.get(`model.${n}`).map(person => EmberObject.create({
      person,
      id: person.id,
      selected: false,
    }))).reduce((a, b) => [...a, ...b], []);
  }
),

I've also shown you how you could make it simpler. For role and title you could use a lookup object.

Now this CP should always contain all people, and when more people get loaded async it will update. This is important. Now you can just sort them (or do anything with them):

sortedPeople: computed('people', function() {
  return this.people.sortBy('person.lastName')
})

this will work reliable because whenever new people are added because they are loaded the people CP will retire and sortedPeople will refire.

If you want to use ember-computed-promise it will allow you to utilise an async function which maybe can make your code pretty readable:

sortedPeople: computedPromise('model', async function() {
  const data = await RSVP.hash({
    coordinators: this.get('model.coordinators'),
    ...
  });

  const people = [];
  data.coordinators.forEach(person => people.push(EmberObject.create({
    person: person,
    id: person.id,
    role: 'coordinators',
    title: 'Coordinator',
    selected: false
  })));

  ...


  return people.sortBy('person.lastName')
})

Here you're basically active waiting for the data to load. This has the benefit that it will be pretty easy to show a loading spinner (the result will be reliable null) while with the other solution the data gets added as it comes.

I won't explain in detail how to utilise PromiseArray because I would strongly recommend to move away from Proxy Objects in ember 3.1+ because you can't utilise native getters for them.

Lux
  • 17,835
  • 5
  • 43
  • 73
  • i tired to work with answer you provided which is the solution using computed properties. but unfortunately it didnt work. as i said before the people contains many profiles. profile contains last name which is not loaded when people are loading. so the computed property sortpeople will not trigger when there is an update for the profile.lastname please find the updated code in the question above – Thilina Dinith Fonseka Oct 19 '18 at 07:21
  • i dont want to use promises cause my next target is to update this code base to 3.x – Thilina Dinith Fonseka Oct 19 '18 at 07:26
0

if you need a detailed answer i used this answer to solve my issue

Sort Ember Object Array with Promises