Skip to content
Kory Nunn edited this page Apr 10, 2014 · 1 revision

To reference data in the model, you an use a path. A path looks like this:

'[/items]'

Syntax

An empty relative path:

'[]'
// Accesses <Current scope>

A simple relative path:

'[someProperty]'
// Accesses <Current scope>.someProperty

A nested relative path:

'[users/0]'
// Accesses <Current scope>.users[0]

An absolute path:

'[/someProperty]'
// Accesses <Model Root>.someProperty

A nested absoulte path:

'[/someProperty/0]'
// Accesses <Model Root>.users[0]

If the leading slash is ommitted, the path is relative, and any Ancestors may affect how the path is resolved.

How do they work

Tip: It's easy to try out path in Gaffa by using the gaffa.model.set, and gaffa.model.get methods.

Gaffa will resolve a path in a number of ways.

In the most simple scenario, paths just map to keys on an object:

// Set a very basic model:
gaffa.model.set({
    someProperty: 1234
});

// Get someProperty
gaffa.model.get('[someProperty]'); // -> 1234

// Set someProperty
gaffa.model.set('[someProperty]', 9876);

Paths can also reference properties on deeply nested objects:

// Set a more realistic model:
gaffa.model.set({
    users:[
        {
            firstName: 'bob',
            surname: 'smith',
            age: 50
        },
        {
            firstName: 'john',
            surname: 'johnson',
            age: 30
        }
    ]
});

// Get the users firstName
gaffa.model.get('[users/0/firstName]'); // -> 'bob'

// Set the users age
gaffa.model.set('[users/0/age]', 51);
// users[0].age will now be 51.

Getting relative.

Gaffa will resolve paths within expressions on a ViewItem based on the ViewItem's ancestors.

The algorithm is as follows:

let paths be an empty array.

Given a Property, push the path in its .binding into paths

Then push it's .path into paths

Then push it's .sourcePath into paths

Then repeat for its parent.

So, given the following structure:

var myTextbox = new Textbox();

myTextbox.value.binding = '[age]';

myTextbox.path = '[0]';

var myContainer = new Container();

myContainer.path = '[users]';

// Add myTextbox as a child of myContainer.
myContainer.views.content.add(myTextbox);

the path in myTextboxs' value binding would resolve to:

'[/users/0/age]'

What is this .sourcePath I see above?

the .sourcePath property is an internally set property used on views, such as a List, that generate child views.

the .sourcePath property is set by the List, when it creates a child, to tell the child where in the model it should be scoped to.

This allows items in a template to bind to the data that they have been created to represent.

An example:

var myTextbox = new Textbox();

myTextbox.value.binding = '[age]';

var myList = new Container();

// Here we bind the Lists list Property to a path that references the users in the model.
myList.list.binding = '[users]';

// set myTextbox as the Lists template.
myList.list.template = myTextbox;

The above List will generate a new Textbox View for every user.

Each generated Textbox will have its .sourcePath set to the path for that key, so that it can use relative bindings to access data at the appropriate location in the model.

In the above example, the first generated Textbox view would look like this:

{
    _type: 'textbox',
    sourcePath: '[0]',
    value: {
        binding: '[age]'
    }
}

and its value Property binding would resolve to:

'[/users/0/age]'

Each user in the model would get a Textbox rendered for it, whos .value Property would be bound to the users age.