@each не обновляет вычисленное значение суммы

В маршруте с моделью массива мне нужна пара сводных статистических данных. Эти сводные статистические данные необходимо обновлять на основе значений, введенных в числовые поля ввода. Я попытался реализовать это, установив их как вычисляемые свойства, используя @each в контроллере.

Свойства (creditTotal и costTotal) вычисляются при загрузке, но не обновляются, когда значения обновляются через поля ввода. К сожалению, их нужно обновлять, и я не знаю, как это сделать.

По общему признанию, я не являюсь разработчиком, работающим полный рабочий день, поэтому я благодарен за любую помощь и понимание, которые вы можете предложить.

06:40PST 03 января 2018 г .: я также поместил это в репозиторий GitHub (https://github.com/knu2xs/arcgis-credit-calculator), чтобы, надеюсь, сделать его немного проще для тех, кто не жалеет своего времени, чтобы внимательно изучить его.

Вот соответствующие файлы, начиная с контроллера.

// ./app/controllers/index.js

import Controller from '@ember/controller';
import { computed } from '@ember/object';

export default Controller.extend({
  creditTotal: computed.sum('[email protected]', function(){
    return this.get('model').mapBy('creditCost');
  }),
  costTotal: computed.sum('[email protected]', function(){
    return this.get('model').mapBy('cost');
  })
});

Далее, модель, на которую ссылаются.

// ./app/models/credit-object.js

import DS from 'ember-data';
import { computed } from '@ember/object';

const _creditCost = 0.1;

export default DS.Model.extend({

  name: DS.attr('string'),
  description: DS.attr('string'),
  creditRate: DS.attr('number'),
  unitRate: DS.attr('number'),
  units: DS.attr('number', { defaultValue: 0 }),

  rate: computed('creditRate', 'unitRate', function(){
    return Number(this.get('creditRate')) / Number(this.get('unitRate'));
  }),
  creditCost: computed('rate', 'units', function(){
    return this.get('rate') * this.get('units');
  }),
  cost: computed('creditCost', function(){
    return this.get('creditCost') * _creditCost;
  }),
});

И маршрут.

// ./app/routes/index.js

import Route from '@ember/routing/route';

export default Route.extend({
  model() {
    return this.get('store').findAll('credit-object');
  }
});

Наконец, шаблон, так что, надеюсь, он имеет какой-то смысл.

<table class="table table-striped table-sm">
  <thead>
  <tr>
    <th scope="col">Name</th>
    <th scope="col">Credit Rate</th>
    <th scope="col">Unit Count</th>
    <th scope="col">Credit Count</th>
    <th scope="col">Cost</th>
  </tr>
  </thead>
  <tbody>
  {{#each model as |creditObject|}}
    <tr>
      <td>{{creditObject.name}}</td>
      <td>{{creditObject.rate}}</td>
      <td>{{input type='number' value=creditObject.units}}</td>
      <td>{{format-floating-point creditObject.creditCost}}</td>
      <td>{{format-currency creditObject.cost}}</td>
    </tr>
  {{/each}}
  <tr class="table-primary">
    <td>Total</td>
    <td></td>
    <td></td>
    <td>{{format-floating-point creditTotal}}</td>
    <td>{{format-currency costTotal}}</td>
  </tr>
  </tbody>
</table>

person knu2xs    schedule 02.01.2018    source источник
comment
попробуйте добавить '[email protected]' в вычисляемые свойства (computed.sum(here, '...', func...). также, пожалуйста, покажите модель вашего маршрута!   -  person Jeff    schedule 03.01.2018
comment
Если я не ошибаюсь, computed.sum() принимает только один аргумент, зависимый ключ. См. документацию.   -  person ykaragol    schedule 03.01.2018
comment
@Джефф, я начал с прямой ссылки на свойства, как вы упомянули, но эти свойства также вычисляются сами по себе, и я не знал, было ли это корнем проблемы, поэтому я наблюдал фактическое изменение свойства. На самом деле я удалил сумму несколько минут назад для проверки, и, что интересно, она показывает полный массив в пользовательском интерфейсе с изменением затронутого значения при ссылке на creditCost и cost. Следовательно, проблема связана с sum, а не с вычисляемым свойством, отслеживающим другое вычисляемое свойство.   -  person knu2xs    schedule 03.01.2018
comment
@ykaragol, это то, с чего я начал, и только что попробовал то, что кажется таким, как это должно быть реализовано таким образом. this.get('model').sum('creditCost') К сожалению, при этом я получаю сообщение об ошибке TypeError: this.get(...).sum is not a function. Я на правильном пути? Этот метод имеет для меня логичный смысл, но, похоже, не работает. Какие-нибудь мысли?   -  person knu2xs    schedule 03.01.2018


Ответы (3)


В конце концов я нашел решение путем множества проб и ошибок. Хотя это и не самое элегантное решение, именно оно в конечном итоге сработало с Ember.js версии 2.18.

creditArray: computed('[email protected]', function(){
  return this.get('model').mapBy('creditCost');
}),
creditTotal: computed.sum('creditArray')

Я наткнулся на запрос на улучшение, в котором обсуждалось объединение этих типов функций, чтобы оно могло стать чем-то вроде этого.

this.get('model').mapBy('creditCost').sum()

В настоящее время это не работает, но я определенно надеюсь, что это будет в будущем!

person knu2xs    schedule 04.01.2018

creditArray: computed('[email protected]', function(){
  return this.get('model').mapBy('creditCost');
}),
creditTotal: computed.sum('creditArray')

Я наткнулся на запрос на улучшение, в котором обсуждалось объединение этих типов функций, чтобы оно могло стать чем-то вроде этого.

this.get('model').mapBy('creditCost').sum()

В настоящее время это не работает, но я определенно надеюсь, что это будет в будущем!

Вы должны различать макросы вычисляемых свойств (например, calculated.sum) и встроенные функции массива JavaScript (например, mapBy). Вышеупомянутое невозможно, потому что в javascript нет функции sum, но ее можно легко реализовать с помощью reduce.

this.get('model').mapBy('creditCost').reduce((res, val) => res + val)
person Eduard Baitinger    schedule 04.01.2018

Попробуй это:

// ./app/controllers/index.js

import Controller from '@ember/controller';
import { computed } from '@ember/object';

export default Controller.extend({
  creditTotal: computed.sum('model.@each.{units}', function(){
    return this.get('model').mapBy('creditCost');
  }),
  costTotal: computed.sum('model.@each.{units}', function(){
    return this.get('model').mapBy('cost');
  })
});

С '{' должно работать нормально

person Shimu    schedule 03.01.2018
comment
Я попробовал это, но выдало ошибку. Как вы можете видеть в приведенном выше обсуждении, после еще немного проб и ошибок, похоже, что я делаю что-то неправильно в том, как я использую функцию sum, но еще не понял это точно... - person knu2xs; 03.01.2018