Breeze JS applications typically rely on some 3rd party library to display entity values in HTML and update entity values from user input entered through HTML controls. Breeze refers to these as “model libraries”.
Each library has its own approach to constructing the HTML and wiring that HTML to the model objects that Breeze calls “entities” such that data can flow to and from the HTML without the developer’s direct intervention.
Each library expects to get and set model values in its own way. Some libraries (AngularJS, Aurelia, React) get and set values through the model object’s own properties. Other libraries (Backbone, Ember, Knockout) get and set values through special “property accessor and mutator” functions.
These differences mean that there is no universal way for Breeze to create an entity. When Breeze creates an entity, as it does when you call
createEntity or when materializing query results, it has to adapt each entity instance to the requirements of the model library you’ve chosen for your application.
Enter the Breeze “Model Library Adapter”.
The “Model Library Adapter” helps Breeze create an entity that conforms to your chosen model library.
Breeze has three adapters at the moment; their names are:
There is no adapter for Ember at this time. It’s on the road-map although, as an open source project, we’d welcome an adapter contributed by you.
All Model Library Adapters are different. But some things are true for all of them.
The default Model Library Adapter may be just right for your application. Whether it is or isn’t, you can always specify your choice of Model Library Adapter explicitly with the following statement that simultaneously chooses and initializes the adapter:
breeze.config.initializeAdapterInstance('modelLibrary', <adapter-name>, true);
The “adapter-name” is likely to be one of the three names listed above. If you were choosing the “backingStore”, you’d write:
breeze.config.initializeAdapterInstance('modelLibrary', 'backingStore', true);
If you specify a Model Library Adapter, you must do so before fetching or creating any metadata. If you create a
MetadataStore first, it will be configured for the ambient Model Library Adapter which may not be the one you want.
For any given application, there can be one and only one active Model Library Adapter. The application can’t switch Model Library Adapters. You can’t have one entity model configured for Knockout and another entity model configured for AngularJS … not in the same application. Think of the active Model Library Adapter as a static Breeze service.
We do switch adapters in our tests; you can see that in the entityExtensionTests.js of our DocCode sample. But this isn’t something you should be doing.
While every Model Library Adapter defines its own way to get and set entity values, Breeze provides a common, method-based approach for getting and setting values (
setProperty) that is available regardless of the adapter you choose. For example, the following always works
customer.setProperty('name', 'Acme'); // set the 'name' property var custName = customer.getProperty('name'); // get the 'name' property
These methods makes it easy to write tests of Breeze functionality without worrying about which Model Library Adapter is currently in play.
Now let’s look at the three adapters shipped with Breeze.
Use the “backingStore” adapter when your model library expects to get and set model object properties directly, e.g.
customer.name = 'Acme'; // set the 'name' property var custName = customer.name; // get the 'name' property
This is the right adapter choice for AngularJS, Aurelia, and React.
The breeze-angular bridge selects this adapter for you automatically while also configuring Breeze to use other AngularJS components.
The “backingStore” adapter is the default adapter (but see the “ko” exception below) so you don’t have to choose it explicitly. But you can be explicit if you wish by executing the following statement before defining a
breeze.config.initializeAdapterInstance('modelLibrary', 'backingStore', true);
The “backingStore” adapter implements all entity data and navigation properties as defined properties with getters and setters. That means you can only use the “backingStore” adapter with modern browsers.
The referenced page lists compatible browsers and versions. Note that IE8 does not support defined properties and is incompatible with the “backingStore” adapter.
Knockout (“ko”) is a popular library for databinding views to observable objects. The Durandal framework incorporates Knockout.
Knockout can databind one-way to model object properties. But if you want two-way databinding with Knockout - and most apps do - the entity must expose observable properties.
Knockout observable properties are actually methods (functions) with same names as their corresponding
customer('name', 'Acme'); // set the 'name' property var custName = customer('name'); // get the 'name' property var orders = customer('orders'); // get the observable array of customer orders
The “ko” Model Library Adapter creates new Breeze entities with observable property methods for each data and navigation property defined in the
Breeze automatically chooses the “ko” Model Library Adapter for you when it detects that you’ve loaded the “knockout” library. You may prefer to choose it explicitly by executing the following statement before defining a
breeze.config.initializeAdapterInstance('modelLibrary', 'ko', true);
Such objects expose two observable property methods,
set that are used as follows:
customer.set('name', 'Acme'); // set the 'name' property var custName = customer.get('name'); // get the 'name' property
The “backbone” Model Library Adapter creates new Breeze entities that inherit from
Backbone.Model and expose the backbone
The backbone developer must choose this adapter explicitly by executing the following statement before defining a
breeze.config.initializeAdapterInstance('modelLibrary', 'backbone', true);
The Model Library Adapter plays an important part in creating an entity object. Clearly, if a model library requires specialized functions to access and mutate entity values, Breeze must add those functions to the model object. But there is plenty more to do even if the model library gets and sets data properties directly.
A Breeze entity object is more than its data values. It has navigation properties to reach related entities. It has an
entityAspect that encapsulates certain “entity-ness” features of the object related to persistence and validation.
And a Breeze entity monitors property-level changes. The data and navigation properties identified in metadata are “tracked” which means Breeze detects when you change a property value and takes one or more actions such as:
entityAspect.propertyChangedevent for that property
entityAspect.entityStatefrom “Unchanged” to “Modified”
Writing a Model Library Adapter is an advanced task. If you’d like to write your own, you should first review the current adapters in the github source. The adapter source file names include the phrase “breeze.modelLibrary”.
Model Library Adapters implement five public members.
name - the name of the adapter, e.g., “backingStore”. Specify this name when choosing this adapter for your app.
initialize - Initializes the adapter itself; called prior to first use.
getTrackablePropertyNames - Gets the names of the properties of an
EntityType that will be monitored for changes.
initializeEntityPrototype - Configure an entity prototype that Breeze will use to create new instances of an
EntityType for this model library.
startTracking - Configures a new entity instance with the properties and/or methods that implement tracked access to the data and navigation “properties”. Called when creating a new entity - more specifically, when creating the
EntityAspect for a new entity - either via the
createEntity method or during materialization of entity data in a query response.