ember.jsember.js-view

EmberJS: How to call a component function from a controller and calculate the component data


I created a route lets say logs (pods structure) and I created the controller.js, route.js and template.hbs

In the template I initialized a grid component. Also I'm working on a custom pagination component.

When I initialize the grid component I have as attributes the data which will change after changing page from pagination and also I want to calculate the page size, how many rows fit in the grid container. And by having the pageSize I can calculate the totalPages.

I have the function of calculating the pageSize in the grid component but I want that number in my controller.js. I managed that by sending the action and I have successfully the number on my controller.

Then on dataHandler computed property I would like to compute the data which the grid will show. There I got the deprecation error and also nothing is displayed in the grid:

DEPRECATION: A property of was modified inside the didInsertElement hook. You should never change properties on components, services or models during didInsertElement because it causes significant performance degradation. [deprecation id: ember-views.dispatching-modify-property]

Is this scenario possible? If yes what is the best way to do it?

Below my code:

logs/controller.js

export default Ember.Controller.extend({
  dataHandler: Ember.computed('pageSize', {
    set(key, value) {
      if (value) {
        this.set('pageSize', value);
      } else {
        this.set('pageSize', null);
      }
      return value;
    },
    get() {
      let data = this.get('data');
      if (!data) {
        let pageSize = this.get('pageSize');
        data = this._data(); //Here will calculate the data and pass them to component
        this.set('data', data);
      }
      return data;
    }
  }),
  actions: {
    setPageSizeFromDataGrid(pageSize) {
      this.set('dataHandler', pageSize);
    }
  }
});

logs/template.hbs

<div class='row'>
  <div class='col-md-12'>
    <h1>Request Logs</h1>
    {{#si-data-grid data=dataHandler rowHeight=35 pageSize="setPageSizeFromDataGrid"}}
      //some content
    {{/si-data-grid}}
  </div>
</div>

my component.js

export default Ember.Component.extend({
  didRender() {
    let that = this;
    that._calculateContainerHeight();

    let children = that.childViews;
    let rowHeight = that.rowHeight || 20;

    let data = that.data;

    let columns = that._parseColumns(children);
    let pageSize = that.getPageSize(rowHeight);

    that.sendAction('pageSize', pageSize);

    Ember.$(that.get('element')).find('div#si-data-grid').kendoGrid({
      columns: columns,
      dataSource: new kendo.data.DataSource({
        data: data
      })
    });

    Ember.$(that.get('element')).find('div#si-data-grid tr').css('height', rowHeight);

 },
 getPageSize(rowHeight) {
   let paginationHeight = 40;
   let gridHeaderHeight = this.$().offsetParent().offset().top;
   let height = this.$().height() - gridHeaderHeight - paginationHeight;
   return Math.floor(height / rowHeight);
 }
});

Solution

  • I managed to find a solution to my problem.

    In my component.js i added the didInsertElement and schedule afterRender to send the action

    export default Ember.Component.extend({
      didInsertElement() {
        Ember.run.scheduleOnce('afterRender', this, '_updateChildViews');
      },
      didRender() {
        //some code
      },
      _updateChildViews() {
        let that = this;
        let rowHeight = that.rowHeight;
        let pageSize = that._getPageSize(rowHeight);
        this.sendAction('updateData', pageSize);
      }
    });
    

    on logs/template.hbs

    <div class='row'>
      <div class='col-md-12'>
        <h1>Request Logs</h1>
        {{#si-data-grid data=dataHandler rowHeight=35 updateData='updateData'}}
            //some code
        {{/si-data-grid}}
      </div>
    </div>
    

    and on my logs/controller.js

    export default Ember.Controller.extend({
      dataHandler: Ember.computed('pageSize', {
        set(key, value) {
          if (value) {
            this.set('data', this._data());  //calculate the data to be shown on the data grid component      
          } else {
            this.set('data', []);
          }
          return this.get('data');
        },
        get() {
          let data = this.get('data');
          if (!data) {
            this.set('data', []);
          }
          return data;
        }
      }),
      actions: {
        updateData(pageSize) {
          this.set('dataHandler', pageSize);
        }
      }
    });