I have this Backbone model:
graphModel
attributes
country
indicator
year
With a corresponding view:
graphView
render()
this.model.get(...)
The application also has a general datasource to which csv data is loaded:
dataSource
indicators
indicatorA
country
year
indicatorB
countries
years
Every time the model attributes are changed, I'd like to check if data for that combination of attributes is loaded, before firing change events.
My question is: What is a good way of decoupling the data source from the Backbone model and view so that I can easily try with injected mock data?
I'm a little unclear when you're talking about the application having a data source populated with CSV data whether you're speaking about the server side of an app that Backbone then talks to or something client side.
But either way. I can speak to our experiences on some of this decoupling stuff. We often build models and use Backbone's ability to have "default" values like this example from the Backbone docs:
var Meal = Backbone.Model.extend({
defaults: {
"appetizer": "caesar salad",
"entree": "ravioli",
"dessert": "cheesecake"
}
});
With a model pre-populated like that we can then tie a view to the model and render that data to the page. Similarly, if you have any other source you can think of for easily getting the data you want (a canned file can be loaded with jQuery's .load() function or the contents of a text area could be dumped in via the model's .set() function).
As far as I understood, you have single URL for different models and you want to somehow check it before you set or change model.
You can use parse() method on model to change it's content, see http://documentcloud.github.com/backbone/#Model-parse
Related
When rendering a Backbone.View you generally pass it the current state of the model model.toJSON() and maybe a few extra properties. This is a synchronous task.
How do you deal with attributes on the model which require async tasks like an id of another model which needs to be fetched from the server (eg person_id)
Do you resolve and attach the person attributes in to the models attributes before sync and render or do you render the view and listen to the person fetch event to re-render that part of the view after?
NB. I am using Backbone.Marionette so am a little limited to changing the render method
The answer is: it depends :-)
Depending on circumstances, you either:
fetch the model from the server, then display the view
update the model that is already displayed
Usually if you're displaying "new" data (i.e. the whole model needs to be fetched), I would display a loading view while the data is being fetched, then display the new view (and data) when it has been fetched (see https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/apps/contacts/show/show_controller.js)
But in other cases (e.g. the user returns to a list of "you might also like" product, such as on Amazon), you can display the data you have on hand, fetch "fresh" data, and rerender the view.
All in all, it really depends on the user experience you want to provide.
I have an array of items populated by an AJAX call in a knockout ViewModel, which displays a few fields of data for each item on a web page.
Now I need to enable the user to click on one item populating a side bar with data which was received from the previous AJAX request (a few fields plus a lot more).
I suppose typically one would take an id and do an item specific AJAX request, routing it through Sammy.js, but we don't need to.
I'm new to knockout; best policy I imagine is to have a ViewModel for the various divs to display the data, but how to get the ViewModels to pass data between themselves? Is this taboo?
Making reference to the other window via the window object?
Using the with: keyword? It keeps cropping up, but I can't see how to apply that in this context.
Perhaps going via Sammy.js, and caching the data in Amplify?
This is an example of drill-down functionality, and I've read a number of StackOverflow Q&A about this but couldn't find up something I can use. I've got up to this stage by following John Papa's PluralSight tutorial.
You may want to go with a pub/sub model either with Amplify's messaging or the library the #RPNiemeyer mentions above. Both are excellent.
However it sounds like you just want to grab the data from the server, then use that data in multiple view models. Perhaps even sharing some of that data in multiple view models. The datacontext concept in my SPA tutorial allows you to host data in the datacontext and reference it from other view models.
You could also use a library like Breeze to help do this (Breeze would replace the datacontext in my SPA ... and be better at it as I will show in an upcoming course).
These are just a few options
You may also want to checkout the "Share an EntityManager" post under "Cool Breezes" in the breeze documentation.
The sharing a single EntityManager is probably all you need. But if you think you need more than one, read "Multiple managers".
IMO The easiest way to do it is to simply pass "params" with an observable containing data to your sidebar component.
http://knockoutjs.com/documentation/component-custom-elements.html#passing-observable-expressions
As was mentioned in comments, the good choice would be to use knockout-postbox
knockout-postbox is a Knockout.js plugin designed to use Knockout's basic pub/sub capabilities to facilitate decoupled communication between separate view models / components.
This allows you to set up simple topic-based communication like:
var ViewModelOne = function() {
this.isEditable = ko.observable();
};
var ViewModelTwo = function() {
this.editable = ko.observable(false);
};
var one = new ViewModelOne();
var two = new ViewModelTwo();
var editableTopic = "myEditableTopic";
one.isEditable.subscribeTo(editableTopic);
two.editable.publishOn(editableTopic)
I'm trying to implement a MVVM based Single Page Application and currently am using the framework Knockout.js to handle the viewmodel/view portion of MVVM. I'm confused though, as every example I've looked at for implementing Knockout involves saving an entire viewmodel to the database. Aren't these examples missing a "model" step, where the viewmodel syncs with the data-layer model and the model does validation / Server synchronization.
I would like to have multiple different templates/views on the single page each with a different viewmodel. Another thing that I find is missing with knockout.js is synchronizing a single model (not viewmodel) across different views. I don't think it makes sense to have one giant viewmodel that every view shares, so I was thinking that each view would have its own viewmodel but each viewmodel would sync with the fields of just a few application-wide models that are needed for each view.
The page I'm working on fetches a giant model (30+ fields, multiple layers of parent/child relationships) and I think it makes sense to just have all of my viewmodels sync with this model. I have investigated Knockback.js (which combines knockout.js and backbone.js) however I ended up re-writing the majority of the functions such as fetch, set, save, because the page is getting data from an API (and I can't just sync an entire model back and forth with the server) so I decided against it.
visual example of my application:
(model layer)
M | M
(viewmodel/view layer) VM-V | VM-V | VM-V | VM-V
another example
An example model would be User = {firstName: "first", lastName: "last", ... }
one viewmodel only needs first name, another viewmodel only needs last name
ViewModelA={firstName: app.User.firstName()}ViewModelB={firstName: app.User.lastName()}
Is the only way to do this to define a pub/sub system for Model and Viewmodel changes? Is this even good/maintainable architecture? Am I missing a basic concept here? All advice welcome.
If I read this correctly, there's a lot of questions in here all focused on how to build a MVVM / SPA with Knockout. There are a few things to tackle, as you pointed out. One is how to communicate between viewmodel/view pairs.
Master ViewModel
One way to do that is to have a master viewmodel as the answer from #Tyrsius. Your shell could have a viewmodel that binds more available data. The master viewmodel could orchestrate the child view models, too. If you go this route then you have to be careful to bind the outer shell to the master viewmodel and the inner ones to specific HTML elements in the DOM. The master viewmodel could facilitate the communication between them if need be.
Decoupled View/ViewModel Pairs
Another option is to use viewmodel/view pairs and no master viewmodel. Each view is loaded into a region of the DOM and bound on its own. They act as separate units and are decoupled from one another. You could use pub/sub to then talk between the, but if all you need is a way for the data to be synched through observables, Knockout provides many options. The one I like is to have each viewmodel surface model objects. So a view has a viewmodel which surfaces data (from a model) that is specific for the view. So many viewmodels may surface the same model in different ways. So when a view updates a viewmodel property (that is in a model) it then ripples to any other loaded viewmodel that also uses the same model.
DataContext
Going a bit further, you could create a datacontext module that manages the data in the models. You ask the datacontext for a model (ex: list of customers) and the datacontext checks if it has them cahced already and if not, it goes and gets them from an ajax call. Either way that is abstracted from the view model and models. The datacontext gets the data and returns a model(s) to the viewmodel. This way you are very decoupled, yet you can share the data (your models) via the datacontext.
I could go on and on ... but please tell me if this is answering your question. If not, happy to answer any other specifics.
** Disclaimer: I'm building a Pluralsight course on SPA's (using Knockout and this strategy) :-)
This is a popular field of interest right now, so I expect you will get some better answers, but here goes.
The Model
Yes, you should absolutely have a server-side representation of the data, which is your model. What this is depends on your server, and your database. For MVC3, this is your entity model. For Django or Ruby, your will have defined db models as part of your db setup. This part is up to your specific technology. But agian, yes you should have a model, and the server should absolutely perform data-validation.
The Application (ViewModel)
It is recommended that your views each have their own viewmodel. Your page could then also have a viewmodel, an App Viewmodel if you will, that keeps track of all of them. If you go this route, the app viewmodel should be responsible for switching between the views, and implementing any other application level logic (like hash bashed navigation, another popular single page tool). This hierarchy is very important, but not always simple. It will come down to the specific requirements of your application. You are not limited to one, flat viewmodel. This is not the only possible method.
Ad Hoc Example:
var ThingViewModel = function(name, data){
this.name = ko.observable(name);
//Additional viewmodel stuffs
};
var AppViewModel = function(initialData){
//Process initial data
this.thing = new ThingViewModel(someName, someData);
};
I am working on a similar project right now, purely for study (not a real world app), that is hosted here on GitHub, if you would like to take a look at some real exmaples. Note, the dev branch is quite a bit ahead of the master branch at the moment. I'm sure it contains some bad patterns (feel free to point them out, I am learning too), but you might be able to learn a few things from it anyway.
I have a similarly complex solution in which I am reworking a WPF application into a web version. The WPF version dealt with complex domain objects which it bound to views by way of presenter models.
In the web version I have implemented simplified and somewhat flattened server-side view models which are translated back and forth from / to domain objects using Automapper. Then those server-side view models are sent back and forth to the client as JSON and mapped into / onto corresponding Knockout view models (instantiable functions which each take responsibility for creating their children with sub-mapping options) using the mapping plugin.
When I need to save / validate my UI, I map all or part of my Knockout view model back to a plain Javascript object, post it as JSON, the MVC framework binds it back to server-side view models, these get Automapped back to domain objects, validated and possibly updated by our domain layer, and then a revised full or partial graph is returned and remapped.
At present I have only one main page where the Knockout action takes place but I anticipate that like you, I will end up with multiple contexts which need to deal with the same model (my domain objects) pulled as differing view models depending on what I'm doing with them.
I have structured the server side view model directories etc in anticipation of this, as well as the structure of my Knockout view models. So far this approach is working nicely. Hope this helps.
During a project i developed a framework (which uses KnockoutJS) which provides decoupled View/ViewModel pairs and allows to instantiate subviews in a view. The whole handling of the view and subview instantiation is provided by the framework. It works like MVVM with XAML in WPF.
Have a look at http://visto.codeplex.com
I have read and even run a sample application that is fully implemented on backboneJS and Django. But am kinda lost how backboneJS is handling this stuff. I need a simple dummy explanation on how backboneJS is receiving the JSON data, building the model, building the collections and listing the data in its view.
Data is displayed in html div tag called "#person"
This is the RESTful/JSON data coming from my server
{"objects":[{"id":"1","name":"John","age":"20", "gender":"male"},{"id":"2","name":"Mary","age":"30","gender":"Female"}]}
Things am looking for in the explanation are;
What is the first function/object created/called by BackboneJS ( entry point )
How does backboneJS tell the views to display the data received?
How does backboneJS model map to the individual fields in the JSON data (id, name, age)
How can i peep in the collections/models created by backboneJS using browser javascript console?
If i have a data entry form with the same fields as the JSON data, using backboneJS, how will i be able to POST the data back to the server, which objects/functions will backboneJS use to perform this task?
Any extra information will be highly appreciated.
Gath
1. What is the first function/object created/called by BackboneJS ( entry point )?
Backbone.js follows MVC architecture. Model defines the actual structural design of model. View defines how the application visually displayed. This view will create the instance of Model and it will be used in the application.
So, in backbone application, Instance of view is created first. When we create an instance of View by calling new myView();, initialize() function will be called first. Model can be instantiated from View as per the requirements.
2. What is the first function/object created/called by BackboneJS ( entry point )?
When you create the instance of model, you can provide the data through that instance. There are getters and setters available for Model.
For example, User is the Model for above JSON. Model is instantiated as below.
var user=new User({“id”:”1”,””name”:”john”,”age”:20,”gender”:”male”});
You need to access the JSON object to define the model.
3.How does backboneJS model map to the individual fields in the JSON data (id, name, age)?
As said before, individual fields can be mapped while instantiating or with the getter and setters of backbone.js
4.How can i peep in the collections/models created by backboneJS using browser javascript console?
You can console the java script objects with toJSON() function. Usually, underscore.js provides more utility functions in backbone.js.
You need to browse through backbone.js documentations.
Addy Osmani did a fine job of explaining that and going even bit more into details down here -> https://github.com/addyosmani/backbone-fundamentals
I've been trying to learn to work with Models and Stores. But the proxy bit is confusing me a lot. So I'm going to list out my understanding here - please point out the gaps in my understanding.
My understanding
Models are used to represent domain objects.
Models can be created by ModelManager, or by simply using the constructor
Models are saved in Stores
Stores may be in memory stores, or can be server stores. This is configured using Proxy.
Proxy tells the store how to talk to a backing store - be that a JSON array, or a REST resource, or a simply configured URL via ajax.
Stores are responsible for storing models, and Proxies are responsible for controlling/helping with that task.
When a model's values are changed, its dirty flag gets set. It gets automatically cleared when the model is saved. (more in this later)
The part that confuses me
Why is there a proxy config and save method on Model? I understand that models can only be stored on to stores.
Why is the dirty flag not cleared simply when I add a model object to a store?
When I add a model object to a store, why does the model not acquire the proxy configured with that store?
proxy is a static configuration for a Model. Does that mean that we cannot use objects of a particular model with multiple data sources? By extension, does this mean having multiple stores for a single model essentially useless?
When we define a Store, are we defining a class (store-type, if we may call it that), or is it an instance of a store? Reason I ask is when we declare a grid, we simply pass it a store config as store: 'MyApp.store.MyStore' - does the grid instantiate a grid of that type, or is it simply using the store we've already instantiated?
Thanks!
PS: +50 bounty to the person who explains all this :) - will offer bounty after those 48 hours are over..
The docs say:
A Model represents some object that your application manages.
A Store is just a collection of Model instances - usually loaded from a server somewhere.
Models are saved in Stores
Not only. The Models can be used separately (f.i. for populating forms with data. Check out Ext.form.Panel.loadRecord for more info).
Why is there a proxy config and save method on Model? I understand that models can only be stored on to stores.
As I've said, not only.
Why is the dirty flag not cleared simply when I add a model object to a store?
Why should it? The Record becomes clean only when it gets synchronized with the corresponding record on the server side.
When I add a model object to a store, why does the model not acquire the proxy configured with that store?
This is, again, because model can be used without store.
proxy is a static configuration for a Model. Does that mean that we cannot use objects of a particular model with multiple data sources?
We cannot use objects of a particular model but we can use one model definition for multiple store. For example:
Ext.define('MyModel', {
// ... config
});
var store1 = Ext.create('Ext.data.Store', {
model: 'MyModel',
// ... config
proxy: {
// ...
// this proxy will be used when store1.sync() and store1.load() are called
}
// ...
});
// ...
var storeN = Ext.create('Ext.data.Store', {
model: 'MyModel',
// ... config
proxy: {
// ...
// this proxy will be used when storeN.sync() and storeN.load() are called
}
// ...
});
Since store1 and storeN use different proxies, the records, contained by these stores, may be completely different.
When we define a Store, are we defining a class (store-type, if we may call it that), or is it an instance of a store?
Yes, when we define a Store, we are defining a class.
Reason I ask is when we declare a grid, we simply pass it a store config as store: 'MyApp.store.MyStore' - does the grid instantiate a grid of that type, or is it simply using the store we've already instantiated?
There are couple of ways to set store config for grid:
store: existingStore,
store: 'someStoresId',
store: 'MyApp.store.MyStore',
In the first and the second cases existing instances of stores would be used. In the third case newly created instance of 'MyApp.store.MyStore' would be used. So, store: 'MyApp.store.MyStore', is equal to
var myStore = Ext.create('MyApp.store.MyStore', {});
// ...
// the following - is in a grid's config:
store: myStore,
UPDATE
When a model is added to store and then the store's sync() is called, why is the model's dirty flag not cleared?
It should be cleared, unless reader, writer and server response are not set up properly. Check out writer example. There is dirty flag being cleared automaticaly on store's sync().
if a model class is not given any proxy at all, why does it track its dirty status?
To let you know if the record was changed since the creation moment.
What is achieved by introducing the concept of Models syncing themselves to the server?
Let's assume you are creating a widget which contains plain set of inputs. The values for this inputs can be loaded from db (this set of inputs represents one row in db table). And when user changes the inputs' values data should be sent to the server. This data can be stored in one record.
So what would you use for this interface: one record or a store with only one record?
Standalone model - is for widgets that represent one row in db table.
Store - is for widgets that represent set of rows in db table.
I'm coming from ExtJS 2.2 [sic] to 4, and the Model behavior and terminology threw me for a loop too.
The best quick explanation I can find is from this post in the "Countdown to ExtJS 4" series on Sencha's blog. Turns out a Model acts like it does because it's "really" a Record.
The centerpiece of the data package is Ext.data.Model. A Model
represents some type of data in an application - for example an
e-commerce app might have models for Users, Products and Orders. At
its simplest a Model is just a set of fields and their data. Anyone
familiar with Ext JS 3 will have used Ext.data.Record, which was the
precursor to Ext.data.Model.
Here's the confusing part: A Model is both a model for the data you're using and a single instance of an object following that model. Let's call its two uses "Model qua model" and "Model qua Record".
This is why its load method requires a unique id (full stop). Model qua Record uses that id to create RESTful URLs for retrieving (and saving, etc) a single Record worth of data. The RESTful URL convention is described here and is linked to in this post on Sencha's blog that talks specifically about Model usage.
Here are a few RESTful URLs formed to that standard to get you familiar with the format, which it appears ExtJS' Model does use:
Operate on a Record with id of 1
GET /people/1 <<< That's what's used to retrieve a single record into Model
return the first record with id of 2
DELETE /people/2
destroy the first record with id of 7
POST /people/7?_method=DELETE
Etc etc.
This is also why Models have their own proxies, so that they can run RESTful operations via that URL modified to follow the conventions described in that link. You might pull 100s of records from one URL, which you'd use as your Store's proxy source, but when you want to save what's in the single Model (again, think "Model qua Record" here), you might perform those Record-specific operations through another URL whose backend messes with one record at a time.
So When Do I use Stores?
To store more than one instance of that Model, you'd slap them into a Store. You add lots of Models qua Records into Stores and then access those "Models" to pull data out. So if you have a grid you'll naturally want to have all that data locally, without having to re-query the server for each row's display.
From the first post:
Models are typically used with a Store, which is basically a
collection of Model instances.
And, of course, the Stores apparently pull info from Model qua Model here to know what they're carrying.
I found it in the documentation of sencha App Architecture Part 2
Use proxies for models:
It is generally good practice to do this as it allows you to load and
save instances of this model without needing a store. Also, when
multiple stores use this same model, you don’t have to redefine your
proxy on each one of them.
Use proxies for stores:
In Ext JS 4, multiple stores can use the same data model, even if the
stores will load their data from different sources. In our example,
the Station model will be used by the SearchResults and the Stations
store, both loading the data from a different location. One returns
search results, the other returns the user’s favorite stations. To
achieve this, one of our stores will need to override the proxy
defined on the model.