view models and binding

46

Upload: evantrimboli

Post on 17-Aug-2015

136 views

Category:

Software


3 download

TRANSCRIPT

Page 1: View models and binding
Page 2: View models and binding

Sencha Inc. ©2015

ViewModelsand Data Binding

Page 3: View models and binding

Evan TrimboliSr. Software Engineer, Sencha

Sencha Inc. ©2015

Page 4: View models and binding

Sencha Inc. ©2015

Why ViewModels

•Automate connection between data and view• Keep view in sync with data• Update data with user input

•Declarative instead of imperative

Page 5: View models and binding

Sencha Inc. ©2015

MVVM

ViewViewMode

l Model

Business LogicandData

Presentation and view logic

Binding

Page 6: View models and binding

Sencha Inc. ©2015

Binding

Page 7: View models and binding

Sencha Inc. ©2015

Binding Essentials

•The “bind descriptor” is a value that describes the desired data.•The “bound value” is the desired data delivered by the ViewModel once it becomes available.•The bound value will be delivered again whenever it changes.

Page 8: View models and binding

Sencha Inc. ©2015

Direct Binding

var vm = new Ext.app.ViewModel();

var b = vm.bind('{foo}', function (v) { console.log(v);});

vm.set('foo', 42); // b.setValue(‘42’);

b.destroy();

1

2

3

Bind descripto

r

Bound value

> 42

Binding instance

4

Marks dependencies as dirty

Page 9: View models and binding

Sencha Inc. ©2015

Negated Binding

vm.bind('{!x}', function (v) { console.log(v);});

vm.set('x', 'world');

Bind descripto

r

> false

Page 10: View models and binding

Sencha Inc. ©2015

Binding Templates

vm.bind('Hello {x:capitalize}', function (v) { console.log(v);});

vm.set('x', 'world');

Bind descripto

r

> Hello World

Page 11: View models and binding

Sencha Inc. ©2015

Objects and Arrays

vm.bind({ x: 'x={x}', y: ['{y}'] }, function (v) { console.log(v);});

vm.set('x', 42);// wait for it...

vm.set('y', 13);

Bind descripto

r

> { x: 'x=42', y: [13] }

Page 12: View models and binding

Sencha Inc. ©2015

Bind Optionsvm.set(‘foo’, {bar: 1});

vm.bind('{foo}', this.onFoo, this, { deep: true, single: true, twoWay: false});

// Without deep, foo won’t changevm.set(‘foo.bar’, 100);

Deliver changes to child object properties

Deliver just the initial

value (once available)

Don’t write-back changes, mark binding

readOnly

Page 13: View models and binding

Sencha Inc. ©2015

Bind Concepts in Depth

•Bind descriptor – the data you want.•Bind token – the replaceable parts (“{foo}”) of a bind descriptor (single name or dot path).•Dot path – the traversal of objects and properties starting at the root of the ViewModel.•Bound value – the value delivered by the ViewModel as the result of a bind request.

Page 14: View models and binding

Sencha Inc. ©2015

Bind Descriptor

•String with one token (“{foo}”) or direct bind.•String template (“Hello {foo}”).•Object whose values are bind descriptors. {foo: “{bar}”}•Array whose elements are bind descriptors.[“{foo}”, “{bar}”]

Page 15: View models and binding

Sencha Inc. ©2015

Bind Tokens

•Simple identifiers (“{foo}”) to select top-level values in the ViewModel.•A “dot-path” to the desired value (such as “{ticket.reporter.name}”).•Formatters such as “Hi {foo:capitalize}” or “Amount {num:round(2)}”.•Negated token (“{!foo}”).

Page 16: View models and binding

Sencha Inc. ©2015

Dot Path

•Normal object property.• Field from a data record (“{user.name}” not “{user.data.name}”).•The associated record of a “to-one” association (“{order.user.name}”).•The associated store of a “to many” association (“{user.orders}”).

Page 17: View models and binding

Sencha Inc. ©2015

Bound Value

•The exact value from the VM if a “direct bind” (just one token).•The boolean negation of the value if a negated direct bind (such as “{!foo}”).•A string with all tokens replaced and formatted (such as “{num:round(2)}”).•An object or array with all property values or elements replaced by their bound value.•A store or record instance.

Page 18: View models and binding

Sencha Inc. ©2015

Componentsand

ViewModels

Page 19: View models and binding

Sencha Inc. ©2015

Config Binding

Ext.define('App.view.Main', { ...

items: [{ xtype: 'button', bind: { text: 'Sign out, {user.name}' } }]});

bind config

Page 20: View models and binding

Sencha Inc. ©2015

Config Binding Options

Ext.define('App.view.Main', { ... items: [{ xtype: 'button', bind: { text: { bindTo: '{foo}', single: true } } }]});

Bind descripto

r

Bind options

Page 21: View models and binding

Sencha Inc. ©2015

defaultBindProperty

[{ xtype: ‘button’, bind: ‘{theText}’ // text}, { xtype: ‘textfield’, bind: ‘{theValue}’ // value}, { xtype: ‘grid’, bind: ‘{theStore}’ // store}]

•Components have a default bind property, which maps to the most common usage for that component

Page 22: View models and binding

Sencha Inc. ©2015

Two Way Binding

var p = new Ext.panel.Panel({ bind: { title: ‘{theTitle}’ }, viewModel: { data: {theTitle: ‘Foo’} }}); // Not twoWayBindable, won’t update VMp.setTitle(‘Bar’);

•Configs that cannot be changed by the user are typically not two way bindable by default.

Page 23: View models and binding

Sencha Inc. ©2015

What ViewModel does that bind use?

Page 24: View models and binding

Sencha Inc. ©2015

Component Tree

viewport panel toolbar button grid panel panel toolbar button

viewport panel toolbar button grid panel panel toolbar button

ViewModel

ViewModel

Page 25: View models and binding

Sencha Inc. ©2015

ViewModel Inheritance

viewport

panelpanel

toolbar

button { bind: '{foo}'}

ViewModel

...

Page 26: View models and binding

Sencha Inc. ©2015

ViewModel

Page 27: View models and binding

Sencha Inc. ©2015

ViewModel Hierarchy

ViewModel

ViewModel

{ }

{ }

data

prototype

data

parent

Page 28: View models and binding

Sencha Inc. ©2015

Populating ViewModels

•Direct set() calls•Configs• data• stores• formulas• links

Page 29: View models and binding

Sencha Inc. ©2015

Data

Page 30: View models and binding

Sencha Inc. ©2015

ViewModel – Data

Ext.define('App.view.main.Main’,{ extend: 'Ext.panel.Panel', xtype: 'main',

viewModel: { type: 'main', data: { foo: 42 } }});

Ext.define('App.view.main.MainModel', { extend: 'Ext.app.ViewModel',

alias: 'viewmodel.main',

data: { foo: 427, bar: ‘baz’ }});

Page 31: View models and binding

Sencha Inc. ©2015

ViewModel – Data (2)

Ext.create({ xtype: 'main',

viewModel: { data: { foo: 42 } }});

ViewModel type comes

from the class

Data is merged, “bar” still

exists

Page 32: View models and binding

Sencha Inc. ©2015

Stores

Page 33: View models and binding

Sencha Inc. ©2015

ViewModel – Stores

Ext.define('App.view.main.MainModel’, { extend: 'Ext.app.ViewModel', alias: 'viewmodel.main',

stores: { bar: { model: 'User’, filters: [{ property: 'name', value: '{form.search}' }] }...

Object is a bind

descriptor

Page 34: View models and binding

Sencha Inc. ©2015

ViewModel – Store Types

Ext.define('App.view.main.MainModel', { extend: 'Ext.app.ViewModel', alias: 'viewmodel.main',

stores: { bar: { type: 'personnel', ... } }});

Ext.define('App.store.Personnel', { extend: 'Ext.data.Store',

alias: 'store.personnel',

proxy: ...});

Page 35: View models and binding

Sencha Inc. ©2015

Formulas

Page 36: View models and binding

Sencha Inc. ©2015

ViewModel – Formulas

Ext.define('App.view.main.MainModel', { ...

formulas: { twice: function (get) { return 2 * get('x'); }, quad: function (get) { return 2 * get('twice'); }

Use the getter

Formulas can use each

other

Page 37: View models and binding

Sencha Inc. ©2015

ViewModel – Two-Way Formulas

Ext.define('App.view.main.MainModel', { ...

formulas: { twice: { get: function (get) { return 2 * get('x'); }, set: function (v) { this.set('x', v / 2); } }

Called when

dependency

changes

this == VM

Page 38: View models and binding

Sencha Inc. ©2015

Links

Page 39: View models and binding

Sencha Inc. ©2015

ViewModel – Links

Ext.define('App.view.main.MainModel', { ...

links: { ticket: { type: 'Ticket', id: 427 }

Load record or request

from Session

Page 40: View models and binding

Sencha Inc. ©2015

ViewModel – Links

Ext.create('App.view.form.Form', { ... viewModel: { links: { ticket: theTicketInstance, user: { type: ‘User’, create: { name: ‘Foo Bar’ } } } }}

Already loaded but may copy

Create a new instance.

May also be true to

create empty record

Page 41: View models and binding

Sencha Inc. ©2015

ViewModel – Links (Ext JS 6)

Ext.define('App.view.main.MainModel', { ...

links: { foo: { a: '{some.object.foo}', b: '{other.thing.bar}' } }}

Object is a bind

descriptor

Page 42: View models and binding

Sencha Inc. ©2015

The Scheduler

Page 43: View models and binding

Sencha Inc. ©2015

Shared Scheduler

ViewModel

ViewModel

parent

Scheduler

Page 44: View models and binding

Sencha Inc. ©2015

Scheduler

Binding[0]

items

Binding[X]

…Data dependencies

Execution

Scheduler

Page 45: View models and binding

Sencha Inc. ©2015

Running The Scheduler

vm.bind(’Hello {type} {thing:capitalize}', function (v) { console.log(v);});

vm.set(‘thing', 'world');vm.set(‘type’, ‘cool’);

vm.notify(); Update all dirty bound values

Page 46: View models and binding

Questions & Answers

Thank YOU!

Sencha Inc. ©2015