creating new entities in Backbone Marionette for related models - javascript

I've built the backbone app with one model ("conference"). Now I added second model ("talk"). talks belongs to conference, conference has many talks. The nested json is created and it is easy to render it into single-conference template with .eco like this:
I can basically build nested json and render nested attributes, no problem but is it a good architecture? Later it will have more layers , every talk will have many comments. What I should do?
Should I build new entities "talks" and use Backbone - associations?
What is the right way to deal with models relations.
My code is based on backboneonrails tutorial and it is very structured: https://github.com/lipenco/talkingheads
I want to maintain good architecture while going into related models.

It's not good to store objects in model's attribute. You can have problems with 'change' event not triggered if you change value of properties in attribute that is object.
So I think it's better to create separate model for talk. You can do all association work manually or use library for that: http://backbonerelational.org/

Related

Require.js/Backbone.js: several views are using the same collection

at first I've to say that I'm not a frontend guy. ;) But in my leisure time I'm working with JS. Currently I'm working on a single page app which uses require.js and Backbone.js. I really like this both libraries!
To my problem:
I've a backbone collection which gets its information from the backend via the fetch() function. This collection only holds data which will not change. The information will be needed to describe a game unit which is defined in the backend. I need the collection for two backbone views, but it's not necessary to fetch the data again. It would be enough to fetch it once, but since I'm using require.js I've to create a new instance of this object. What is the "right" way to solve this problem? Singleton, global object? And I'll have more collections which only holds data which will not change during over the runtime.
If the collection will never change (i.e. the data on the cleitn won't be changed after being received form the server), simply provide the same collection instance to your various views.

How to ensure that JS anonymous objects continue to map onto POCO ViewModels

We have an ASP.NET MVC application that extensively uses AJAX calls.
These AJAX calls send data to our controller method - this controller method requires an argument which is a simple POCO ViewModel class.
In our JavaScript we create an anonymous object whose properties map onto the properties of our ViewModel, and the MVC framework handles all the routing so that in the controller method we get our ViewModel with all the properties.
All well and good.
What we want to do is to put in place a robust way to ensure that the JavaScript anonymous class and the ViewModel class remain in-synch - if a developer changes one then they change the other. We can of course put in comments in both files to say "change one, change the other", and a threat of a severe beating for the developer who fails to keep these in synch, but even with code reviews this is an area that may be missed.
It would be great to have some kind of automated unit test that could check for this, but I'm not aware how to achieve this.
Any suggestions?
Thanks in advance
Griff
There is a javascript library called knockoutjs and it is used exactly for what you are trying to achieve. It seems like you are trying to use the MVVM pattern with the ASP.NET MVC framework. With any MVVM pattern, it's a common problem to keep your viewmodel in sync with the view. KnockoutJS allows you to created javascript viewmodels client-side that bind directly to the view. The viewmodels get updated when the view is updated and the view is updated when the viewmodel is updated. KnockoutJS uses a common pattern called the Observer pattern to acheive this. KnockoutJS also provides a mapping plug in so the viewmodels can receive server-side viewmodels in JSON format and update itself, thus updating the view. This is the functionality that you are looking for. The library and the mapping plugin can be found on their website, www.knockoutjs.com. FYI...it is a producation level library. They also have great documentation and examples. I hope this helps. don't re-invent the wheel.

Backbone - shared model

I started reading some Backbone tutorials and I found one thing that astonishes me. Why models are created inside of view? What if I want two different views for one model (what I think MVC is for)? Let's say I need a model Colors, DisplayView view which displays them and ControlsView which allows me to set their configuration. How to handle this?
Backbone does not require that you create your models inside your views - you can (and often should) create your models independently of your views so that they can be shared. Also, just because you create a model inside a view doesn't mean you can't pass a reference to that model to another view and share it that way.
Most likely the tutorials you are reading are very simple and create single models for single views to make the tutorial easier to follow.

Backbone.js - What is the best approach for global/shared/related models?

I'm currently building an application using Backbone.js with a number of different models that all relate to each other in various ways. I'm currently experimenting with various architectural approaches.
In a nutshell the model relationships looks something like this:
Workspace > Projects > Tasks
There are a few other models, such as lists and categories, that are attached to a project.
On a page with a task list, I'm dumping the JSON of the tasks onto the page and filling up the collection. This works ok, but at the moment all tasks are pulling in their own project data.
task.project.id
task.project.name
The projects are also being pulled in various other locations on the page for various lists. Tasks can also be part of a List which is assigned to a Project. This means I'm also making requests to pull in the lists for a project in various places as well.
The main problem with this is that when updating a model in place I need to find some way to 'sync' them. Which is crazy. They should all be using the same model instance so that each view is using the same model and is updated accordingly without having to do anything.
I've been researching various Backbone.js architectural designs to try and find the answer. Chaplin (https://github.com/moviepilot/chaplin), for example, uses a mediator object to pass data between views. Using this approach, I could have a Projects collection on the mediator and pass this around to the various views via the mediator object.
Each project would include all of it's lists, categories, assigned users etc. Then I could request for a project model like so:
App.Projects.get(12)
Then the task would just need the project ID and a getter and setter method. Views could get access to available projects, project lists, project users easily as well without relying on digging into the model or making further AJAX calls. Additionally, the task models wouldn't require any of the project data on them.
However, dumping all this data in a global object seems bad.
I would possibly end up with something like this:
App.Workspaces
App.Workspaces.get(1)
App.Projects
App.Projects.get(12).get('lists')[0]
App.Projects.get(12).get('users')
To use like this:
var projectId = model.get('project')
var project = App.Projects.get(projectId)
Or with a getter method:
var project = model.getProject()
And add the mediator as a dependency at the model level instead.
Adding a large global object like this adds a fairly large dependency that could make testing difficult. It also seems wrong to assume that the mediator will even have the project available. Maybe it could make the model, fetch it and return it if it doesn't exist.
Any help here would be great! I'd love to know how other people have solved this problem.
I recommend to have a common Collection for all your Task Models. Kind of cache.
Something like: App.Store.Tasks.
Any time you need to feed the Poject.Tasks look first in the App.Store.Tasks and then:
A. If you found the Task there then take it and add it to your Project.Tasks.
B. If not found there then create, fetch and add it to both: App.Store.Tasks and your Project.Tasks.
This way other Project that tries to fetch a Task that already exits will do the same and they both will share the same Model.
Any time you modify one of your Task models in a Project you'll be modifying this Task in every other Project.

Backbone: Are Views really Controllers?

I'm building my first Backbone.js app and I'm confused about how much responsibility I'm supposed to give to or hide from my Views.
In my example, I'm building a Rich UI Table (similar to YUI's datagrid) that's dynamically generated from a Collection. In my app I call this an "AppTable". In my understanding of MVC, I would imagine that there'd be some kind of AppTable controller which finds the correct Collection, grabs a "dumb" View and passes to the View whatever information from the Collection it needs to render. In this senario, the View would do little more than take the data provided to it and modify the DOM accordingly, maybe even populating a template or attaching event listeners.
Backbone seems to do away with the idea of having a controller mediate between the View and Collection. Instead a View gets initialized with a reference to a Collection and it is View's responsibility to update itself.
Am I understanding this architecture correctly?
Assuming I do, my question then becomes, what happens when my View needs to do more and more? For example, I want column sorting, drag-and-drop for rows, pagination, searching, table control links (like new, copy, delete row... etc), and more. If we stick with a "smart" View paradigm where the View is connected directly to a Collection, do the above functions become attached to View object?
Thinking through this, I could see the View growing from a simple table wrapper to pretty messy beast with lot of functionality attached to it. So, is the View really a controller in this case?
Your understanding of the architecture is correct. Backbone does not recognize the concept of a "controller" in the traditional MVC sense. (In fact, Backbone used to actually have an object called a Controller, but it has been renamed Router to more accurately describe what it does.)
The functions you list (drag-drop, delete rows, sorting, etc.) would all belong in a View. A view describes what you see and responds to user input. Anything involving an event (a click, a keypress, a submit, etc.) all go inside of a view. But your view should never actually manipulate the data; that should be done by its model. You are correct in thinking that a view acts like a controller, because it packages data and sends it to the model, which will then validate/set/save appropriately. Once those actions have occurred, the view re-renders itself to represent the new version of the data inside the model.
One note of caution: your view should not be too strenuously tied to the DOM. It is Backbone convention to have a top-level DOM element that your view is tied to (e.g., a form or a div) and then deal only with its sub-elements. That is appropriate; in general, things like "remove this link from this div" inside your view are not. If you find your view growing unwieldy, you most likely need to break it into subviews, each with their respective behaviors as components of their whole.
My thoughts on this updated below:
I think Josh gave a good answer, however, in my experience, building a few Backbone apps, even medium-complexity apps do need a separate controller class.
To clarify what I mean about a controller: The functionality between the model (or router) and the view that creates and instantiates the new view class and kills (and unregisters events) on the old one. This functionality might be the same for many views (so a direct one-to-one relationship between views and controllers probably isn't needed) but sometimes one needs to pass in a model or other additional extra values.
Right now, I just have one controller with a few if statements for adding some unique data to certain views for most apps I've built but I'm looking at setting up an architecture where it will check to see if a unique controller exists for that view else it falls back to the standard controller. Nothing special, but should do the job.
Update: After six months of building Backbone apps I realized that routers can be split up and extended just like views. (duh?)
Right off the bat, I knew to make a base view of functionality I know that all my views would need. Similarly, I would make base views for each section, like "profile" pages or "inbox" pages that I know would all use the same functionality. This wasn't so clear to me in the beginning with routers, but the previous name of "Controller" hinted at this.
Most people (as in every example of Backbone I've ever seen on the web) just use one monolithic router instantiation to handle all routes but you can actually have 1-to-1 parity of routers to views, or in my case, a base router for checking user auth and such and then one for each major section. That way if you need to pass in certain models or collections to a router on page load, you don't need to add code to one monolithic router, but instead pull up the unique router for that view. I find this is currently better than creating a separate controller class. The base router can be in charge of last instantiated view, etc, so you can kill the last view before instantiating the new one.
TLDR: Use multiple Routers as controllers. I believe that's what they were meant for and it works well.
I've struggled with the same semantic issues when trying to map out a single-page app. In the end I decided that Backbone is using the wrong name.
When you look at a Backbone app in the browser, the View is not actually a view at all, its el member is the view. Backbone.View is either a view controller or, probably more correctly, a presenter.
Some supporting evidence:
you never see a Backbone.View on the screen, its always the el or $el that is applied to the DOM
a Backbone.View does not receive user input, the DOM element receives input and the events are delegated via the events hash of the "view"
a BackBone.View manages model or collection changes and translates these changes to dumb-view (DOM) elements, then applies them to the actual view, e.g. this.$el.append('<p>Cats!')
I think Backbone.Presenter would be a better name, but I can also see the historical issues with there being a former Backbone.Controller and the amount of work renaming introduces.
I have settled on the following structure for my latest project:
an app controller, extended from Backbone.View, tied to the body element
several model collections to cache data retrieved from the server
a Backbone.Router that translates route changes into Backbone events and triggers them on itself
many app controller methods that handle the router events the app controller listens to
an app controller method prepares any needed models, then initiates a presenter (extended from Backbone.View) and attaches it to the body element
All these parts are initiated and owned by the app controller. The presenters do not know why or where they are on the page and only care for their own DOM elements and the changes they receive from this.model.
Have a look at this part of backbone documentation
http://documentcloud.github.com/backbone/#FAQ-tim-toady
References between Models and Views can be handled several ways. Some
people like to have direct pointers, where views correspond 1:1 with
models (model.view and view.model). Others prefer to have intermediate
"controller" objects that orchestrate the creation and organization of
views into a hierarchy. Others still prefer the evented approach, and
always fire events instead of calling methods directly. All of these
styles work well.
So, backbone does not take that decision for you.
I have a very similar use case (table grid with pagination, ordering, live filtering, and forms with client-side validation, master-details relations, etc.)
In my case, I first started with a Router behaving just like a controller, and quite quickly my code got a bit messy.
So I completely removed Routers (I'll add them back later, but just as an addition) and created my own controller (that in fact works as a presenter). It's just a javascript class, with Backbone.extend backed in to handle inheritance.
The idea is that the view recieves all the data it needs to display itself (model, collection, and the el in which it should be parsed), set up listener on dom events, and then executes controller methods. It never directly modifies the data nor it interacts with other views, it tells the controller to do it.
A view can have subviews, and in that case the subview only interacts with the parent view, or directly with the controller.
So far now it seems to work, but anyway things are not so simple as I expected them to be...
I hope to publish it in the next few days.
A different perspective from the other answers here is that, just because you are using the Backbone framework, that doesn't mean that your entire codebase must be wrapped in Backbone classes.
Personally, my controller is an amalgamation of "raw" Javascript and Backbone routes, and I never use Views for control logic at all. IMHO views are for ... well, view logic, and specifically for wrapping elements. If you're using a view for anything that doesn't directly connect to an HTML element you are (again, IMHO) doing something wrong.
Backbone is awesome, but that doesn't mean that it's a silver bullet that can be applied to everything.

Categories

Resources