can/merge
Minimally update nested data structures with the response from the server.
canMergeBehavior( baseConnection )
Overwrites can/map's instance callbacks so they use map-deep-merge. map-deep-merge is able to make minimal changes to the nested properties of can-define instances and lists given raw data. E.g:
var existingStudent;
var classroom = ClassRoom.get({id: 505}).then(function(instance) {
instance.id; // 505
instance.students[0].id; // 15
instance.students[0].name; // 'Samantha Jones'
existingStudent = instance;
});
... // later in the program new information for the classroom is retrieved
ClassRoom.get({id:505}).then(function(instance) {
instance.id; // 505
instance.students[0].id; // 15
instance.students[0].name; // 'Samantha Jones-Baker'
// true, if can-merge behavior is used.
// a new nested instance isn't created, instead it was updated with the changed fields
existingStudent === instance.students[0];
});
To use can/merge
, the connection's Map, List and any of their
nested types must be properly configured. That configuration is discussed in the
"Use" section below.
Parameters
- baseConnection
{Object}
:can-connect
connection object that is having thecan/merge
behavior added on to it. Expects the can/map behavior to already be added to this base connection. If theconnect
helper is used to build the connection, the behaviors will automatically be ordered as required.
Returns
{Object}
:
a can-connect
connection containing the methods provided by can/merge
.
Use
To use the can/merge
behavior, you have to:
- Add the behavior after can/map, and
- Make sure all types, especially List type is properly configured.
Adding the can/merge
behavior after can/map is pretty straightforward.
When you create a custom connection, create it as follows:
var canMergeBehavior = require("can-connect/can/merge/merge");
var canMapBehavior = require("can-connect/can/map/map");
var ClassRoom = DefineMap.extend({
...
});
ClassRoom.List = DefineList.extend({
"#": ClassRoom
});
ClassRoom.algebra = new set.Algebra({...})
ClassRoom.connection = connect([..., canMapBehavior, canMergeBehavior, ...],{
Map: ClassRoom,
List: ClassRoom.List
});
For map-deep-merge to merge correctly, it needs to know how to uniquely identify an instance and
be able to convert raw data to instances and lists.
map-deep-merge
looks for this configuration on the .algebra
and .connection
properties of the
Type setting on can-define types.
This is more easily understood in an example.
If the ClassRoom
has a students
property that is a list of Student
instances like:
var ClassRoom = DefineMap.extend({
students: Student.List
});
To be able to uniquely identify Student
instances within that list, make sure Student
has an algebra
property
that is configured with the identifier property:
Student = DefineMap.extend({ ... });
Student.algebra = new set.Algebra(set.props.id("_id"))
Also make sure that Student.List
points its # definition to Student
like the following:
Student.List = DefineList.extend({
"#": Student
});
Note: the typical method used to create a Student
is new Student(props)
.
However, if Student
s have a .connection
, map-deep-merge will use
Student.connection.hydrateInstance(props)
.
This is useful if Student
s should be looked up in the connection instanceStore.
For example, Student
might have a connection that has an instanceStore, like:
Student.connection = baseMap({
Map: Student,
List: Student.List,
url: "/services/students",
name: "students"
});