Hello everyone! I created a purchases controller to take data from user input, but I have an error;
routes/purchases.js:
import Route from '@ember/routing/route';
export default class PurchasesRoute extends Route {
}
controllers/purchases.js:
import Controller from '@ember/controller';
import { action } from '@ember/object';
export default class PurchasesController extends Controller {
@action
addPurchase() {
var pname = this.get('PurchasesController').get('pname');
var pprice = this.get('PurchasesController').get('pprice');
console.log(pname, pprice);
}
}
purchases.hbs:
{{page-title "Purchases"}}
<div class="purchases">
<h3>Add Purchase</h3>
<div class="input-field">
{{input placeholder="Purchase Name" type="text" class="validate" value=pname}}
{{input placeholder="Purchase Price" type="text" class="validate" value=pprice}}
</div>
<a class="waves-effect waves-light btn" {{on 'click' this.addPurchase}}>Add Purchase</a>
</div>
{{outlet}}
error:
Uncaught TypeError: Cannot read property 'get' of undefined
at PurchasesController.addPurchase (purchases.js:15)
Thanks in advance for your help!
Let’s break down what this line of code is doing and I think it will help. Obviously you’re creating a local variable pname, and assigning it a value. The value you’re trying to get is a chain, which is often where you’ll see this error crop up, because one of the “links” in the chain doesn’t exist. Sometimes putting a breakpoint in can help as you can see what vars have what values.
Anyway, first you have this
. In the context of your controller this
is being referenced in an action (you’re using the action decorator), so it is binding the method this
to the controller. So this
is referring to the controller itself. Next in the chain you’re getting PurchasesController
. This is the source of your error. Since this
is already the controller you don’t need this “link” in the chain at all. To say that differently, since this
the controller you’re trying to get PurchasesController
on an instance of PurchaesController
but that property doesn’t exist on the controller so it is undefined. Lastly you’re trying to get another property “pname” from something that doesn’t exist (undefined
) which is why the error is thrown. So in summary you can remove the middle part of the “chain” and just make it this.get('pname')
.
While we’re here I’ll give you a few other recommendations which aren’t strictly necessary but may help a bit. First of all, with Ember Octane (which I’m assuming you are using since you’re using native classes) you don’t usually need to use the get()
method, so you could shorten your action to:
@action
addPurchase() {
var pname = this.pname;
var pprice = this.pprice;
console.log(pname, pprice);
}
and it would work the same way. It might also be worth declaring pname
and pprice
as tracked properties. e.g.
import Controller from '@ember/controller';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracked';
export default class PurchasesController extends Controller {
@tracked pname;
@tracked pprice;
This tells ember to auto-track the values. For more information on autotracking see this page and this page
Lastly, it’s good practice in modern code to make sure template references to things on the backing class (the controller in this case) are prefixed with this
, so your inputs should look like this:
{{input placeholder="Purchase Name" type="text" class="validate" value=this.pname}}
Anyway hope all that helps!
1 Like
THANK you so much! It helps!