Ember 2.x

Ember 2.x Dependencies on Arrays

Topics:

This course has been updated! We now recommend you take the Ember Octane Fundamentals course.

Check out a free preview of the full Ember 2.x course:
The "Dependencies on Arrays" Lesson is part of the full, Ember 2.x course featured in this preview video. Here's what you'd learn in this lesson:

There are two ways computed property dependencies on an array can be declared. They can be declared based the length of an array or based on a property of an item in the array. Mike shares use-cases for when each method is appropriate.

Get Unlimited Access Now

Transcript from the "Dependencies on Arrays" Lesson

[00:00:00]
>> [MUSIC]

[00:00:03]
>> Mike North: There are two ways to declare a dependency on some aspect of an array. One is using square brackets and the other is using this @each notation. The key difference between the two is that when you use square brackets, you're really just observing the size of the array.

[00:00:27] You're watching for things to be added and removed. And in the event that that nature of the array changes, your computed property will be invalidated. And the next time you ask for it, it will be recalculated. The second example here where we're using each.id. What you're doing there is you're actually observing the ID property on every item within this array.

[00:00:56] And so if you were for example building some shopping cart and you wanted to have this computed property called grand total. And you wanted to observe on all of the items in your shopping cart you wanna note the unit price and the quantity. And if those change, if I increase quantity on an individual item even though I didn't add a new thing to my shopping cart I just bumped up quantity, I want to recalculate my grand total.

[00:01:28] This would be the thing to reach for. So you're actually observing the items inside the array not the length of the array itself. Very key distinction to make here. So you would just use these strings here with the square bracket or the @each. You would just pass those in along with firstName, lastName.

[00:01:51] You would just use that string as a way of declaring a dependency on that property. And you can have as many as you want in here. You can even have no dependencies, which is an interesting case. That would be a situation where you would have to explicitly, for example, when an action is called.

[00:02:12] Fire a property change. Say like, I declare this to be invalidated. And that will trigger an update the next time the property's asked for. But just be aware you can have as many dependencies as you want. And it's everything except the last argument passed into computed is taken as a dependency.

[00:02:33]
>> Speaker 2: There's a quick question in chat.
>> Mike North: Yes?
>> Speaker 2: Is there a way to do something like, mylist.each watch all values for change?
>> Mike North: There is deliberately not a way to do that, because that would be terribly expensive. That is observing a whole lot of data, and it's likely to cause things to become invalidated when it's inappropriate.

[00:02:58] If you're in that situation where you're just observing a whole lot it's often much more efficient to not declare that dependency. And to, whenever an action is fired of some sort, you can just, call this method notify property change and pass in the property key. And that will have the same effect as a dependency being changed.

[00:03:25] It effectively invalidates the cache and the next time you ask for that value it will recalculate.
>> Speaker 3: So you don't consume the computed property. It will never calculate the computed property.
>> Mike North: Precisely.
>> Speaker 3: If you don't consume the computed property but you use the setter to do something and you set computed property, does it calculate them?

[00:03:45] Even though that computed property may never be consumed in a get cell?
>> Mike North: So let's look at our setter here. You're essentially not gonna have to really calculate much. You're providing this computed property with a value, so it will have that value. So if I never asked for fullName but I set fullName here, the effect that will have is that fullName will be up to date firstName and lastName will be updated and everything will work as you would expect.

[00:04:19]
>> Speaker 3: So the get is actually cached without having to call the get in that scenario?
>> Mike North: So the act of returning newVal is gonna take care of everything that needs to be taken care of.
>> Speaker 3: That'll cause the cached value to do that for get. So I don't actually have to call get.

[00:04:37]
>> Mike North: Correct.
>> Speaker 3: But I ask for the computed.
>> Mike North: And typically you're gonna have parity between those two things. In this case, you're definitely gonna have parity. There are situations where it's a little bit different. For example, if the conversion from the computed property to what it's dependent on is lossy, so imagine we derive from a float and I am int.

[00:05:01] And so in that case it can be a little bit odd because you lose data going on one leg compared to another.
>> Speaker 3: Punch a developer that makes a setter that is lossy.
>> Mike North: Sometimes you can't get away with, sometimes that's a valid use case. Like if you're dealing with currencies and you have thousandths of a dollar, and you don't want to surface that to your user.

[00:05:26] You-
>> Speaker 3: I would argue that the setter is the wrong way to set the value in that case, cuz there's an implication there.
>> Mike North: It is a far better way than using something like an observer which you should, any time you can use a computed property instead of an observer, you should absolutely be using a computed property.

[00:05:43] That is a blanket statement.
>> Speaker 3: Okay.
>> Mike North: I am never wrong about that.
>> Speaker 3: So that's not I got another awesome use case I wanna show you.
>> Mike North: [LAUGH]
>> Speaker 3: Can you give me one more, just a little bit about the setter return value and why not doing that is buggy?

[00:05:58] Is there something happening behind the scenes that you don't know? Or is it an expectation on the person consuming the object?
>> Mike North: That is going a little too much on the internal.
>> Speaker 3: But it's magic. It's not necessarily about the person consuming it. It's about how computed properties work.

[00:06:17]
>> Mike North: All I'd like to leave you guys with is follow this convention or else you will feel a little bit of pain.
>> Speaker 3: Or else the contract says.
>> Mike North: All right so speaking of the internal.
>> Speaker 2: Do you wanna cover one more?
>> Mike North: Yeah.
>> Speaker 2: They just came up, is volatile not recommended for computed properties?

[00:06:38] Is there a case when it is recommended?
>> Mike North: I, so it exists in its public API. So there probably are use cases. I can say I have written a huge amount of code in Ember and I don't believe I've ever used volatile. I've never found a really great use case for it.

[00:07:01] I imagine that they exist but they are so few And I think that if you structure code a particular way you can usually steer clear of the need for it entirely. Just to clarify volatile means do not cache anything. Recalculate each and every time you're asked for a value.

[00:07:23] And what I opt for is explicitly invalidating the computed property. Wiping out the cache at the right moment usually in an action rather than kind of saying I don't wanna manage caching properly so don't cache at all.