SproutCore

SproutCore Guides

These guides are designed to help you write and perfect your code.

MVC — The model layer.

SproutCore includes a powerful model layer, called the datastore. SproutCore has special code in it’s controller and view layers to make the datastore the most efficient source of data.

This is a Draft Copy, and although the information in here is correct, it may be incomplete in places.

Nevertheless, you don’t have to use the datastore in your application. Like most high-quality frameworks, the datastore is an optional framework in SproutCore (though it is “on” by default).

1 How To Use SproutCore Without a Model Layer

This is how you do what backbone.js does in SproutCore. It does not use SproutCore’s datastore.

See http://www.jamesyu.org/2011/01/27/cloudedit-a-backbone-js-tutorial-by-example/ for an example.

apps/my_app/core.js

var MyApp = SC.Application.create({

  newTask: function() {
    // optional: clear the values in the fields
    MyApp.newTaskPane.append();
  },

  createTask: function() {
    // 1. Fetch the values from the fields in MyApp.newTaskPane.
    var name = MyApp.newTaskPane.get('nameField'),
        description = MyApp.newTaskPane.get('descriptionField');

    // 2. Send the values to the remote "create" method
    //    (disable interaction)
    SC.Request.postUrl('/tasks')
              .header({ 'Accept': 'application/json' }).json()
              .notify(this, '_didCreateTask').send();
  },

  // 3. When the server responds, create the task and add update
  //    MyApp.tasksController.
  _didCreateTask: function(response, store, storeKey) {
    if (SC.ok(response)) {
      var hash = response.get('body');
      MyApp.Task.create(hash);
    }

    // 4. Show the MyApp.editTaskPane
    MyApp.editTaskPane.append();
  },

  updateTask: function() {
    // 1. Get the values from MyApp.selectedTaskController
    var task = MyApp.selectedTaskController.get('content');

    // 2. Contact the server and send the updated properties
    //    for the task (disable interaction)
    // 3. When the server responds, refresh the task with then
    //    new properties.
    MyApp.editTaskPane.append();
  },

  deleteTask: function() {
    // 1. Search MyApp.tasksController for the task with id = `id`.
    var task = MyApp.selectedTaskController.get('content');

    // 2. Contact the server and ask it delete the task with
    //    id == `id` (disable interaction)
    // 3. When the server responds, delete the task and remove
    //    it from the list.
    MyApp.listTasksPane.append();
  },

  showTaskList: function() {
    // 1. Use SC.Response ajax to contact your server.
    // You can hardcode the url in here:
    SC.Request.getUrl('/tasks').json()
        .notify(this, '_listDidRespond').send();
    MyApp.listTasksPane.append();
  }

  _listDidRespond: function(res) {
    // 2. When you get the response, instatiate MyApp.Task objects
    //    and add them to a new array
    var newArray = [];
    var jsonHashesArray = res.get('body');
    jsonHashesArray.forEach(function(hash) {
        var task = MyApp.Task.create(hash);
        newArray.push(task);
    });

    // 3. Set the new array as the "content"
    MyApp.tasksController.set('content', newArray);
  }

});

//
// Define our model class.
//
MyApp.Task = SC.Object.extend({

  toJSON: function() {
    var hash = {}, key, val;

    for (key in this) {
      if (!this.hasOwnKey(key)) continue;

      val = this[key];
      if (val.isProperty) val = this.get('val');
      hash[key] = this.get(key);
    }
  }

}); // gives us the "create" function.

//
// Make our Task list available to views.
//
MyApp.tasksController = SC.ArrayController.create({

  content: [],
  allowsMultipleSelection: NO,

});

//
// Keeps track of the selected task so we can bind to it in
//our views.
//
MyApp.selectedTaskController = SC.ObjectController.create({

 contentBinding: SC.Binding
                   .single('MyApp.tasksController.selection')

)};

//
// Create a pane to display our task list.
//
MyApp.listTasksPane = SC.MainPane.create({

  contentView: SC.View.create({

    childViews: 'list new'.w(),

    list: SC.ListView.create({
      layout: { centerX:0, top:50, width:300, bottom:100 },

      contentBinding: 'MyApp.tasksController.arrangedObjects',
      selectionBinding: 'MyApp.tasksController.selection'

      actsOnSelect: YES,
      action: 'editTask',
      target: MyApp
    }),

    new: SC.ButtonView.create({
      layout: { centerX:60, height:54, width:90, bottom:50 },
      title: "New Task",
      action: 'newTask',
      target: MyApp
    })
  })
});

//
// Create a new task pane.
//
MyApp.newTaskPane = SC.MainPane.create({

  nameField: SC.outlet('contentView.form.name'),
  descriptionField: SC.outlet('contentView.form.description'),

  contentView: SC.View.create({

    childViews: 'form new'.w(),

    form: SC.View.create({
      layout: { centerX:0, top:50, width:300, bottom:100 },

      childViews: 'name description'.w(),

      name: SC.TextFieldView.create({
        layout: { top:10, left:10, right:10, height:80 },
        hint: "Enter a task  name"
      }),

      description: SC.TextFieldView.create({
        layout: { top: 100, left: 10, right: 10, bottom: 10 },
        allowsMultipleLines: YES
      })

    }),

    new: SC.ButtonView.create({
      layout: { centerX:60, height:54, width:90, bottom:50 },
      title: "Create",
      action: 'createTask',
      target: MyApp
    })
  })
});

//
// Create an edit task pane.
//
MyApp.editTaskPane = SC.MainPane.create({

  contentView: SC.View.create({

    childViews: 'form update delete'.w(),

    form: SC.View.create({
      layout: { centerX:0, top:50, width:300, bottom:100 },

      childViews: 'name description'.w(),

      name: SC.TextFieldView.create({
        layout: { top:10, left:10, right:10, height:80 },
        valueBinding: 'MyApp.selectedTaskController.name'
      }),

      description: SC.TextFieldView.create({
        layout: { top: 100, left: 10, right: 10, bottom: 10 },
        allowsMultipleLines: YES,
        valueBinding: 'MyApp.selectedTaskController.description'
      })

    }),

    update: SC.ButtonView.create({
      layout: { right:10, height:54, width:90, bottom:50 },
      title: "Update",
      action: 'updateTask',
      target: MyApp
    }),

    delete: SC.ButtonView.create({
      layout: { right:120, height:54, width:90, bottom:50 },
      title: "Delete",
      action: 'deleteTask',
      target: MyApp
    })
  })
});

main() {
  MyApp.showTaskList(); // Puts the list on the screen.
};

2 Changelog