View
 

Todos 02-Setup Your Model

Page history last edited by Kevan Stannard 14 years ago

This todo tracker will have a simple list of tasks. You can give each task a name and choose whether the task is complete or not.  Let’s set up the model for this:

 

sc-gen model Todos.Task

 

Let’s start by configuring the task model. Tasks have two properties: a description and a completion state (isDone). In SproutCore you define this schema on your model class.

 

Model objects are of the type SC.Record. To tell SproutCore about various attributes in your schema, you declare them as properties on your class.

 

Let’s add these properties to our Task subclass right now. Open up the file at apps/todos/models/task.js and fill in the content of the class:

 

Todos.Task = SC.Record.extend(

/** @scope Todos.Task.prototype */ {

 

  isDone: SC.Record.attr(Boolean),

  description: SC.Record.attr(String)

 

}) ;

 

Helper methods defined in SC.Record are used to describe each data attribute of your model object. These helper methods specify the expected type (Boolean, String, etc.) as well as other constraints. These will sometimes be used to automatically convert properties you set on your record into the proper type, but most often they will be used to perform validation.

 

In the example above, “isDone” is described as a Boolean while “description” is described as a String. SproutCore will automatically convert any values you set into these types if possible.

 

We are almost ready to begin using our object in a live web browser Javascript console. But first, we must set up some test data for us to work with. SproutCore uses fixtures for initial testing data, which removes application dependency on server-side data and allows us developers to rapidly prototype our application. Let's do this now.

 

Open the task fixture file in apps/todos/fixtures/task.js and insert the bolded lines:

 

Todos.Task.FIXTURES = [

 

  { "guid": "task-1",

    "description": "Build my first SproutCore app",

    "isDone": false },

 

  { "guid": "task-2",

    "description": "Build a really awesome SproutCore app",

    "isDone": false },

 

  { "guid": "task-3",

    "description": "Next, the world!",

    "isDone": false }

 

];

 

Getting Down In the Console

 

Now you should have some sample data to work with. Go to your web browser and reload the page. Nothing will look different just yet, but behind the scenes the first three task records have already been created. Open up the console in Safari (cmd + opt + c) or Firebug (F12) and we'll see it in action!

 

Let’s start by finding all of the task records currently installed in the system. You can do this with the following command on the JavaScript console:

 

> tasks = Todos.store.find(Todos.Task)

 

If this doesn't work try to delete the tmp folder in your app root directory and restart the server.

 

If the application's store was connected to a server, this command would return all the tasks recorded on the server-side. However, since fixtures are currently being used, an array-like objects with static fixture data is instead returned.

 

What does “array-like” mean? You might have noticed that we said the object returned by find() was not an Array exactly but “array-like”. In order to support some advanced techniques for working with large data sets, SproutCore defines an interface you can use to work with arrays called SC.Array. This interface is added to the built-in Array object but it is also implemented by several other classes. You can work with array-like objects exactly the same as long as you use the methods defined in SC.Array.

 

Let’s see if this is the data we expect.

 

One useful method SproutCore adds to all array-like objects (including the built-in Array) is getEach(), which will get the property you name on each member object and return the result. We’ll use this to get the description property.

 

Type this into your JavaScript console:

 

> tasks.getEach('description')

 

You should see an array printed with each of the descriptions in your fixtures:

 

["Build my first SproutCore app", 
"Build a really awesome SproutCore app",     
"Next, the world!"]

(From now on, when JavaScript console code is shown, the recommended command will be  preceded by an “>” and the expected output will follow without an angle bracket.)

 

Now let’s try to get the isDone property:

 

> tasks.getEach('isDone')     [false, false, false]

 

Now that you have created a model layer and a set of fixture data, it is time to add an interface. Discover the view building process in the next section.

 

Continue to Next Step: Step 3: Build Your Views » 

Comments (25)

Sridhar Chittiprolu said

at 11:42 pm on Sep 14, 2009

Upto Now This Tutorial is awesome and it makes me more confident to learn this SproutCore Framework. Expecting the same in future references. Thanks for this.

Brandon Tennant said

at 4:52 pm on Sep 29, 2009

There seems to be a bug in this stage of the tutorial.
> tasks = Todos.store.find(Todos.Task)
and then
> tasks.getEach('description')
returns: [null]

Tested both manually following the tutorial and by cloning the Git repository.

Louis Chen said

at 5:39 pm on Sep 29, 2009

@Brandon Tennant: Try using:
tasks = Todos.store.findAll(Todos.Task)
then
tasks.getEach('description')

Hope it helped! :)

Colin Campbell said

at 8:16 pm on Sep 29, 2009

@Brandon Tennant/Louis Chen:

When I was proceeding through this tutorial, I ran into the same issue. store.findAll() is deprecated and should not be used. The problem, for me, was my Sproutcore files being out-of-date. Brandon, if you get the most recent files, it'll start working:

https://sproutcore.pbworks.com/Abbot-Setting+Up

Hope that helps.

Louis Chen said

at 5:37 pm on Sep 30, 2009

@ Colin Campbell:

I do know that we shouldn't be using store.findAll() anymore, but it is kind of the only way that you can go on with the tutorial without getting into more problems. The reason is, after you update your SproutCore files, this .find() problem is solved, but the reordering is messed up. Also, if I can remember clearly, you are going to have trouble adding new tasks too (where the tasks are added but you will have to click manually to edit the content).

Hope they solve those problems in step 5 soon.

Brandon Tennant said

at 10:16 pm on Sep 30, 2009

@Lous Chen
Thanks for the help. Initially i tried this and got a bit further but there was still some strangeness, mostly it returning an empty set.

@Colin Campbell
Also thanks. After upgrading (looks like I tried this tutorial right around the time they moved to the new gem) I'm able to follow this section of the tutorial with no issues.

So updating to the latest ultimately resolved my issue.

Larry Siden said

at 11:06 pm on Oct 25, 2009

As I'm a LInux user, I cannot run Safari (except through Virtualbox). So I have to use Firefox + Firebug. If I enable only the Console tab, and leave the Net and Javascript tabs disabled, Firefox spins for several minutes before it finally settles down and display the page. Has anyone else had to deal with this. Is there perhaps some setting I could change or toggle that would fix this. I can do it in Opera, but I have to remember to append .toString() to the end of each command like "tasks.getEach('isDone')" or all I get back in the console is "[object Array]".

Robert Feldt said

at 12:36 am on Oct 28, 2009

Fresh Ruby 1.9, gems and sproutcore install but get these problems:

tasks = Todos.store.find(Todos.Task)
:4020/static/sproutcore/datastore/en/current/source/system/store.js?1256636806:832Error: SC.Store#find() must pass recordType or query

If I instead use findAll as proposed in comments it seems to work but I then get empty arrays back when querying the tasks object:

tasks = Todos.store.findAll(Todos.Task)
:4020/static/sproutcore/datastore/en/current/source/system/store.js?1256636806:856SC.Store#findAll() will be removed in a future version of SproutCore. Use SC.Store#find() instead
Object

tasks.getEach('description')
[]

Help needed.

Fred Dushin said

at 11:02 am on Nov 2, 2009

Robert,

I had this same issue, undoubtedly because I had some stale SC bits lying around. I followed the instructions for removing SC, and rebooted the tutorial from a blank slate, and find started working again.

> uname -a
Darwin XXXXXXXX 10.0.0 Darwin Kernel Version 10.0.0: Fri Jul 31 22:47:34 PDT 2009; root:xnu-1456.1.25~1/RELEASE_I386 i386
> gem --version
1.3.1
> gem search sproutcore

*** LOCAL GEMS ***

sproutcore (1.0.1009)

Jens Fahnenbruck said

at 2:31 am on Mar 25, 2010

I have the same problem. I have a complete fresh install, since this is the first time I'm trying sproutcore.

My System: OS X 10.6.2, Safari 4.0.5, ruby 1.8.7 (system), gem 1.3.6

Somebody any idea?

Jens Fahnenbruck said

at 5:59 am on May 8, 2010

I was able to solve this problem with deleting the tmp folder in the root directory of the app

bobisjan said

at 10:26 am on Dec 7, 2009

Hi,

can I use records from one app in another app (apps are in the same project)?

I have project which contains two apps: "AddressBook" and "Mail" and I would like to use once defined "AddressBook.Contact" in "Mail" app...

Thanks.

Erich Ocean said

at 5:34 pm on Dec 7, 2009

Bobik, you can put the model definitions in a framework that is required by both of the apps in your project.

globalflea said

at 10:38 pm on Jan 10, 2010

Hi,

After adding the fixtures, i too got an empty result after tasks.getEach('description'). I followed the comments on the Hello World tutorial and deleted the todos/tmp directory and reload the page - it works. But i'm wondering why?

Cory Jacobsen said

at 10:03 am on Apr 13, 2010

If you get hung up with the "tasks = Todos.store.find(Todos.Task)" command, try deleting your tmp folder (found at the root of your project directory). It seems that the project is not rebuilding all the time.

Hope this helps!

Sunny said

at 1:18 am on Apr 16, 2010

Hi, I have the most recent SC files as well as gems.
While following this tutorial when I did : 'sc-gen model Todos.Task' in my terminal, it gives an error : 'FATAL ~ This generator requires a Target'.
Can anyone help me as to how to proceed from here?

Parvez Halim said

at 8:18 am on Apr 24, 2010

Were you able to figure out what was wrong?

Abdullah Jibaly said

at 10:31 am on Jul 2, 2010

Make sure you use the same package name as your folder. If you called you app Hello then use: sc-gen model Hello.Task

Parvez Halim said

at 8:17 am on Apr 24, 2010

I have the same problem as Sunny. Please help. I follow exactly what it says on this page: sc-gen Todos.Task.

Parvez Halim said

at 8:26 am on Apr 24, 2010

Sorry. Very stupid of me. Missed page 1.

jia Feng said

at 4:11 am on Apr 30, 2010

I use sc-gen model Todos.Test create another model, the content of the model file and fixture files are exactly the same with the Task one.
Then I use:
tasks=Todos.store.find(Todos.Task)
everything is OK, but when I use:
tests=Todos.store.find(Todos.Test)
There will be an Error:
SC.Store#find() must pass recordType or query
Does anyone know the reason?

Jens Fahnenbruck said

at 6:01 am on May 8, 2010

Try to delete the tmp folder and then restart the server. That helped me with this

mudphone said

at 7:35 am on Jun 4, 2010

There is an extra comma in the first example on this page:
description: SC.Record.attr(String),

It was giving me warnings in JSLint.

Arthur Park said

at 2:54 pm on Oct 18, 2010

And if will fail to load in IE, if anyone cares about it.

Leankyle said

at 11:34 am on Jul 22, 2010

Very informative post!

You don't have permission to comment on this page.