-
Notifications
You must be signed in to change notification settings - Fork 156
Batman Accessors
This section will literally blow your mind. So hold onto your seat. So what exactly is an accessor? An accessor is a property/function that is attached to a Batman.Object. Yes, I realize that's not really amazing or anything, but here's the kicker. The accessor actually "monitors" the @get calls that you use. That means anytime you use @get and the values changes, the model will react to the change. This is huge people.
Before we get ahead of ourselves, let's go over the basic accessors. Here's the most popular accessors for a model (there are others, these are the most used):
attributes
dirtyKeys
errors
isNew
When a Set it created, these accessors get applied:
first
last
isEmpty
toArray
length
indexedBy
indexedByUnique
sortedBy
sortedByDescending
Model accessors and Set accessors are your most important weapons (from what I've found). So make sure to become familiar with the above accessors as you're going to use them a ton.
Sets are used everywhere, but most importantly they're used when you retrieve data (whether it be from a database, or from localstorage). Have you ever seen code like this and wondered how it works?
<div id="errorz" data-showif="newTemplate.errors.length">
This will show this div(errorz) if newTemplate has errors. Basically, these are chained accessors. The above syntax causes quite a bit of confusion and people think that they are calling "methods", but that's not the case. Remember that because of our 2 way binding we the div(errorz) will show and hide based on having errors.
I recently saw this on the google groups board BAD data-foreach-notice="Notice.all.sortedBy('created_at', 'desc')" BAD in a question. When I first started I did some similar things since the Keypath syntax is kind of weird. Weird but powerful. If anything on the keypath changes, the values will be updated.
John Lynch replied correctly with:
data-foreach-notice="Notice.all.sortedByDescending.created_at"
And if you wanted to sort ascending:
data-foreach-notice="Notice.all.sortedBy.created_at"
If you look in the batman.js code, you'll see that these accessors are "special" accessors that take a key. And that's why we can do "sortedBy.created_at".
indexedBy
indexedByUnique
sortedBy
sortedByDescending
Maybe you want to do your own accessors. Here's a simple example with custom accessors:
Model:
class WordBump.Word extends Batman.Model
@resourceName: 'word'
@persist Batman.LocalStorage
@encode 'name', 'rank'
@accessor 'addOneHundred'
get: -> @get('rank') + 100
Controller:
class WordBump.AppController extends Batman.Controller
routingKey: 'app'
index: ->
# fill the initial wordlist
@set 'wordList', @fillWordList()
fillWordList: ->
wordList = new Batman.Set
words = ['waffle', 'batman', 'ninja', 'rock', 'paper', 'tree', 'fight', 'tall', 'yellow', 'blue']
# loop through all of the words creating word objects
for word in words
wordList.add new WordBump.Word(name: word, rank: 0)
wordList
View:
<div class="ranking">
<div data-foreach-word="wordList.sortedByDescending.rank">
<span data-bind="word.name | prepend 'Word: '"></span>
<span data-bind="word.addOneHundred"></span>
</div>
</div>
Here's the basic setup. When the page loads you'd be looking at something like this:
Word: waffle 100
Word: batman 100
Word: ninja 100
Word: rock 100
Word: paper 100
Now here's where the magic would happen. Let's say I update the rank in the first element of the wordList.
WordBump.get('controllers.app').wordList.toArray()[0].set('rank', 1)
We'll end up with this:
Word: waffle 101
Word: batman 100
Word: ninja 100
Word: rock 100
Word: paper 100
Because we used a @get within our accessor, the accessor "addOneHundred" saw that the rank was updated and added 100 to it (only shown in the front, the actual model still contains rank: 1). This is really mind blowing, and will save you a ton of time.
You can also put accessors on the class like so:
@classAccessor 'completed', ->
@get('all').filter (todo) -> todo.get('completed')
Which would update the Todo.completed accessor with the completed todo items as they become completed.
Another example is an invoice. Let's say you're adding rows to an invoice. You could create a class accessor to watch the invoice rows, and when one is added, automatically calculate the GST and the total.
Your life is made easy by a combination of 2 way binding and accessors.
Questions? @RyanonRails