Abdulelah
Abdulelah

Reputation: 691

Ember binding input value depending on another input

I'm working on Ember JS and I have a weird problem which I found no solution for.

Now I have a form, in this form I have a 'cost' input which takes obviously a cost of an item, right next to it is a select tag from which the user selects the time spending for the entered cost.

If a user spend 10 dollars on the specified item everyday then he should select "Daily" from the select menu, if the 10 dollars are spent "Weekly" the user should select "weekly" and so on and so forth.

Now beneath these two inputs I have four "readonly" tags in which I want to show the user how much he spends "daily" "weekly" "monthly" and "yearly".

But I get an error "Assertion Failed You Modified **** twice ..."

Here is my template:

{{ui-input value=name placeholder="Expense Name" label="Name"}}

{{ui-input value=cost placeholder="Expense Cost" label="Cost" half=true}}

{{ui-select value=costTime default="Expense Time" label="Expense Time" items=formData.expenseTime half=true}}

<div class="col-md-6 no-padding">
    {{ui-readonly value=expense.daily placeholder="Daily" label="Daily" half=true}}
    {{ui-readonly value=expense.weekly placeholder="Weekly" label="Weekly" half=true}}            
</div>
<div class="col-md-6 no-padding">
    {{ui-readonly value=expense.monthly placeholder="Monthly" label="Monthly" half=true}}            
    {{ui-readonly value=expense.yearly placeholder="Yearly" label="Yearly" half=true}}
</div>

and here is what I'm trying to do in my controller

import Ember from 'ember';
export default Ember.Component.extend({
        expense : { daily: '', weekly: '', monthly: '', yearly: '' },
        setExpense : Ember.computed('cost', 'costTime', 'expense.weekly', function() {
            if (this.get('costTime') == 'daily') {
                this.set('expense.weekly', Number(this.get('cost') * 7))
            }
            return this.get('expense.weekly')
        }),
});

Upvotes: 0

Views: 72

Answers (2)

fidlip
fidlip

Reputation: 71

Best pattern is to use DDAU and component didReceiveAttrs hook.

import Ember from 'ember';
export default Ember.Component.extend({
    cost: null,
    costTime: null
    expense : { daily: '', weekly: '', monthly: '', yearly: '' },

    didReceiveAttrs: function() {
        var cost = this.get('cost');
        var costTime = this.get('costTime');
        if (cost && costTime) {
          if (costTime == 'daily') {
            this.set('expense.weekly', Number(cost * 7))
          } else ...
        }
    }
});

and you must pass actions on change cost and costTime to parent component and change it there. edit: Another approach is to define more properties:

import Ember from 'ember';

var multipliers = { daily: 1, weekly: 7, monthly: 30, yearly: 365 };
function computeDailyCost(cost, costTime) {
  var multiplier = multipliers[costTime];
  if (multiplier) {
    return cost / multiplier
  }
}

function defMultCost(multiplierKey) {
  return Ember.computed("cost", "costTime", function() {
    var dailyCost = this.computeDailyCost(this.get("cost"), this.get("costTime"));
    var multiplier = multipliers[multiplierKey];
    if (dailyCost != null && multiplier != null) {
      return dailyCost * multiplier;
    }
  });
};

export default Ember.Component.extend({
    cost: null,
    costTime: null
    daily: defMultCost("daily"),
    weekly: defMultCost("weekly"), 
    monthly: defMultCost("monthly"), 
    yearly: defMultCost("yearly")

});

I did not test this, but it should work.

Upvotes: 0

Gokul Kathirvel
Gokul Kathirvel

Reputation: 1610

I can see that you are trying to set a property expense.weekly inside a computed property setExpense which is considered as an anti-pattern because setting a property inside a computed one may trigger a UI rerender and it's already deprecated. Moreover, from the logic inside the computed property (setExpense), I assume that it is perfectly fit for an action.

You can move the logic to a separate action and trigger it when the select option changes. This will eliminate the backtracking errors which you are facing now.

Alternative: You can compute expense with the help of computed property with the appropriate dependent properties.

expense: Ember.computed('cost', 'costTime', function () {
  let expense = { daily: '', weekly: '', monthly: '', yearly: '' };
  // compute the expense here...
  return expense;
})

Upvotes: 1

Related Questions