Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ember.js - what is the correct controller/view pattern for creating a new model

I have an app which at the moment contains a view of objects of the same model. They are retrieved from the server, looped through and added to the list controller using an add method

<script>
App.Controllers.List = Em.ArrayProxy.create({
  content: Ember.A([]),
  add: function(obj){
    this.pushObject(obj);
  }
});
</script>

I am now working on a part where the user creates a new object that (after passing validation) will be added to the list and also sent to the server.

I can't find any examples on the best patter to follow for creating a new object via an input form. I can see a few options, and have semi-implemented a few but nothing feels right.

  • Create a view with appropriate form elements and a method for instantiating the model using various properties retrieved from the form elements using .get()
  • Create a model in the view's content and bind form elements to that. Include a method on the view for adding to the controller array / saving to the server
  • Create a model, add it to the controller array and open it for editing

I can kind of fight out the functionality I want, but I'd prefer make sure I am aware of best practice.

I currently have something like this (which is the second bullet on my list)

<script>
App.Views.ItemCreate = Em.View.extend({
  content: App.Models.Item.create({}),
  templateName: 'create',
  createButton: function(){

    var itemObj = this.get('content');
    var item = {};
    item.title = this.get('content').get('title');

    $.ajax({
      type: 'POST',
      url: '/test/data.json',
      data: item,
      dataType: 'json',
      success: function(responseData, textStatus, jqXHR) {
        App.Controllers.List.add(itemObj);
      }
    });
  }
});
</script>

<script type="text/x-handlebars" data-template-name="create">
  {{view Em.TextField id="create-title" valueBinding="content.title"}}
  <a href="#" {{action "createButton" }}>Create</a>
</script>

Any help greatly appreciated

NOTES

I've changed the correct answer to pangratz's. Although the other responses directly answered my question, I believe those who find this via Google should refer to the answer Pangratz provided as not only is it good MVC, but it is more Ember-y :o)

like image 880
joevallender Avatar asked Apr 20 '12 08:04

joevallender


People also ask

What is an ember controller?

In Ember. js, controllers allow you to decorate your models with display logic. In general, your models will have properties that are saved to the server, while controllers will have properties that your app does not need to save to the server.

What is model in Ember js?

In Ember Data, models are objects that represent the underlying data that your application presents to the user. Note that Ember Data models are a different concept than the model method on Routes, although they share the same name.

How does Ember js work?

Ember uses templates to organize the layout of HTML in an application. Ember templates use the syntax of Handlebars templates. Anything that is valid Handlebars syntax is valid Ember syntax. Here, {{name}} is a property provided by the template's context.

Is Ember a MVC?

Ember. js is a MVC (Model–View–Controller) JavaScript framework which is maintained by the Ember Core Team (including Tom Dale, Yehuda Katz, and others).


2 Answers

Communicating with the server is definitely something which shouldn't be done in the view. This is something a controller is for. To separate the different parts of the application further, I would even consider implementing a DataSource which handles the AJAX requests. This split makes your application more testable and each components reusable. The concrete connections of view, controller and data source are then realized via bindings.

The workflow for your case could be the following:

  • The view shows your edit form, which' values are bound to a controller
  • The view handles a save action which tells the controller to save the created object
  • The controller delegates the saving to the DataSource which then finally starts the AJAX request
  • The controller is notified when the object has been saved

You should also look at ember-data which is a client side data storage and handles all the boilerplate for you. Also have a look at The architecture of Ember.js apps - data and EmberJS: Good separation of concerns for Models, Stores, Controllers, Views in a rather complex application?


View:

App.View.ItemCreate = Ember.View.extend({
  templateName: 'create',
  createObject: function(evt) {
    var object = this.get('content');
    var controller = this.get('controller');
    controller.createObject(object);
  }
});

Controller:

App.Controllers.List = Ember.ArrayProxy.extend({
  content: [],
  createObject: function(hash) {
    var dataSource = this.get('dataSource');
    dataSource.createObject(hash, this, this.createdObject);
  },
  createdObject: function(object) {
    this.pushObject(object);
  }
});

DataSource:

App.DataSource = Ember.Object.extend({
  createObject: function(hash, target, callback) {
    Ember.$.ajax({
      success: function(data) {
        callback.apply(target, data);
      }
    });
  }
});

Glue everything together:

App.dataSource = App.DataSource.create();
App.listController = App.Controllers.List.create({
  dataSourceBinding: 'App.dataSource'
});

App.View.ItemCreate.create({
  controllerBinding: 'App.listController'
}).append();
like image 160
pangratz Avatar answered Oct 18 '22 05:10

pangratz


If you want to follow a strict MVC model then the model should never be created on the view but on the controller. Ember is still very young and still haven't any defined patterns, what I would do is have your model set as the content of the view (as you have already done) with all the inputs bind to the different model attributes. Then when the button is pushed:

createButton: function(){
  App.Controllers.List.create(this.get('content')); 
}

On the controller:

create: function(model) {
  if model.valid() { //validates the model
    model.save({
      onSuccess: function(response) { // callback
        var item = App.Models.Item.create(response.item)
        App.controllers.List.add(item)
      }
    })
  }

And finally the model:

save: function(options) {
  $.ajax({
    type: 'POST',
    url: '/test/data.json',
    data: item,
    dataType: 'json',
    success: options.onsuccess
  });
}

This is the way other js frameworks expect you to work. It feels a little more verbose and complex, but it keeps the things in place

like image 38
Fernando Diaz Garrido Avatar answered Oct 18 '22 04:10

Fernando Diaz Garrido