Reputation: 691
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
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
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