## Dataset Factory
The dataset factory works in conjunction with the schema. This class will construct classes as defined in the schema per request.

## Schema Structure
The basic structure consists of these three:

1. id
2. name
3. fields

The id is required to identify the dataset in the schema when refered to other schema parts but also when requesting a new instance of a dataset.
The name provides you with a descripor as to what this dataset represents.
Fields define the structure of the dataset.

```json
"datasets": [
    {
        "id": 0,
        "name": "model",
        "visualization-data": true,
        "fields": [
            {
                "name": "selection",
                "dataset": 2
            },
            {
                "name": "header",
                "dataset": 3
            }
        ]
    }
]
``` 
 
### Fields
The field has one required part and that is the name property.
Additional information can be attached to a field that allows further functionality like validation or custom attributes you may need when using the model.
The field definition will be attached to the instance of the model as "__definition"

visualization-data is not a required property and in most cases can be left out. if you set this to true, the data will not wrapped in a dataset.
When using the data in a visualization it needs to be processed in the group worker and it has to be raw data. That is where visualization-data comes in.
I when you are setting a collection field and you define a dataset, and the collection will be used in a visualization 

#### Dataset Field
In some cases you may want a model to have sub models.  
To do this you can define a field as being a model by providing it with a dataset id

```json
{
  "name": "field1",
  "dataset": 2
}
```

During the construction process it will see that you need a instance of dataset with id 2 set as the property name defined.

#### Collection Field
If you want to define a field as being a collection you can define it by setting the collection propert to true and defining the dataset id representing the collection item structure.

```json 
{
    "name": "contacts",
    "collection": true,
    "dataset": 1
}
```

This will create an array, add and remove function.
For example if the property name is contacts the model will look like

```json 
{
    "contacts": [],
    "addContacts": function(),
    "removeContacts": function(id)
}
```

if you want to add to add an contact item you can do it like this:
 
```js
const contact = model.addContacts();
```

to remove a contact with id 1:

```js
model.removeContacts(1);
```

to look or bind to the contacts of the model use:

```js
model.contacts
```

#### Default value for a field
Default allows you to define the default value that the field must be populated with at construction.

```json
{
    "name": "company",
    "default": "my company name"
}
```

After you have created the model and you look at the property "company" you will see that the value is "my company value".
If you do not define a default value the value of the property is null;

When defining a collection, you need to point it at the datasource and the datasource will determine what values to initialize with.
```json
{
  "name": "contacts",
  "datasource": 1 // list of contact objects
}
```

#### Refresh collection on field change
There are a number of scenarios when you want to refresh a collection when a particular property value changes.
This operates on a single dataset.

Collection fields can define a "listen-for" property. The field name defined here must be that of the property on the same model as the collection.
When this field value changes the collection will be told the reload itself. If this collection is a remote collection the normal remote callbacks will be fired.

```json
{
    "name": "collection",
    "datasource": 1,
    "listen-for": "field1"
}
```

In the above example, when field1's value changes the collection field will be asked to reload itself.
A example where this is useful is when you have a contextual seletion where the collection of selectable values depend on what the field value of field1 is.

#### Hierarchial datasource
```json
{
    "id": 0,
    "remote": "assets",
    "query": "parentId=10",
    "hierarchical": true
}
```
A hierarchical datasource is a datasource with a parent, child relationship.
If you set the datasource to be hierarchical the root items will be fetched during the model's setDefaultValues process.
From that point on it is up to the developer to decide when to fetch the children for a given root item.

When working with hierarchical data the class used for each item is HierarchicalItem.
This object has a number of properties you want to take note of.

1. model -> the data property of the hierarchical item
1. isExpanded -> ui property used to determine if a given item is expanded or collapsed
1. hasChildren -> this property is used to determine if a item is a leaf node or can be expanded to fetch children. If set to false you can't expand this item.
1. items -> if you have children, they will be in this array.

Though generally speaking you never need to populate the parent's items property, you can add items to a parent by using the addItem function.

Consider the following dataset
```json
{
    "id": 0,

    "name": "model",
    "fields": [
        {
            "name": "assets",
            "collection": true,
            "datasource": 0
        }
    ]
}
```

The model's asset property is a datasource object.
To fetch the children and populate the parent item's items property with the children you can call the load function on the datasource.

```js
this.model.assets.load(parentItem.model, parentItem);
```

The standard function you set on the dataset factory for collection fetching will be called.
In addition to the normal schema definition and model property a parent property is also provided incase you need it to determine how to filter for children.

e.g.
```js
getDetails(definition, model, parentItem) {

}
```

Hierarchical datasources work regardless if it is a remote datasource or resource based.
This will only affect where the root items are loaded from.
Regardless of the type, when fetching children for a given parent, the above mentioned collection fetching method will be called.

## Creating Dataset Factory

```js 
this.factory = new DynamicFactory(schema, this.modelCreated, this.populateCollection);
```

Now you have a istance of the dataset factory and the models you request must be defined the schema provided.
The second parameter is a construction callback if you want one.
This is typically used when you want to do some additional information on the model after it was constructed but before passed back to caller.

The model callback method has a model parameter where the new model will be passed for processing in the callback.


```js
modelCreated(model) {
    console.log(model);
}
```

The collection populated callback requires you to populate the collection property.
The remote property defined in the schema will be passed on to you as reference.    
You need to return a array of object literals. please note that this must be done sync.

## Listen to model property changes
If you want to be notified that a particular property has changed on the model so that you can do some processing you can do that by using the model's listenFor method.
This function has two parameters:

1. Property name to listen for
2. callback function to call when the value changes

```js 
this.model.header.listenFor("firstName", this.headerChanged.bind(this));
```

The callback struction in this calse looks like this:

```js
headerChanged(model, property) {
    console.log(model[property]);
}
```

This way you can use one function to monitor a number of property changes, though you don't have to do it this way.
If you prefer using different functions you can do that also.

Another way of doing this is by not providing a callback at all but instead define the property change method on the model you are monitoring.

```js 
this.model.header.firstNameChanged = newValue => console.log(newValue);
this.model.header.listenFor("firstName");
```

If you don't define the callback it will look for a method on the model that is a compisite name between the property name and "Changed".
e.g. if you are checking for the firstName property to change you need to set a method on the model called 'firstNameChanged'.

The structure on this method is a bit different in that it will only send you back the new value of the property you are listening for.

## Collection Index
When processing the schema default for a collection it will transform the item to a DataSet class.
It will also set a property on that dataset called "__index" that will indicate the number of that item on the collection.
"__index" starts on 1 and not 0 because printing this on the user interface needs to be 1 based.

## Cleanup memory
The models have a build in dispose function will will clear all the memory and dependencies for you.
If properties are models themselves the model will call those properties dispose methods automatically.
You must however remember to call the dispose method to do the cleanup on the model.

```js
model.dispose();
```

If you don't call the dispose method on the model when you are done with it you will have memory leaks.
