6.1 Models

Models are very simple in nature. Their responsibility is to hold data that can be used by both Controller and View to communicate with each other. In other words, Models are not equivalent to domain classes.

Models can be observable by means of the @Bindable AST Transformation. This actually simplifies setting up bindings so that changes in the UI can automatically be sent to model properties and vice versa.

@Bindable will inject a `java.beans.PropertyChangeSupport` field and all methods required to make the model an observable class. It will also make sure that a `PropertyChangeEvent` is fired for each observable property whenever said property changes value.

The following is a list of all methods added by @Bindable

- `void addPropertyChangeListener(PropertyChangeListener listener)`
- `void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)`
- `void removePropertyChangeListener(PropertyChangeListener listener)`
- `void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)`
- `PropertyChangeListener[] getPropertyChangeListeners()`
- `PropertyChangeListener[] getPropertyChangeListeners(String propertyName)`
- `void firePropertyChange(String propertyName, Object oldValue, Object newValue)`

The following is a list of all methods added by @Vetoable

- `void addVetoableChangeListener(VetoableChangeListener listener)`
- `void addVetoableChangeListener(String propertyName, VetoableChangeListener listener)`
- `void removeVetoableChangeListener(VetoableChangeListener listener)`
- `void removeVetoableChangeListener(String propertyName, VetoableChangeListener listener)`
- `VetoableChangeListener[] getVetoableChangeListeners()`
- `VetoableChangeListener[] getVetoableChangeListeners(String propertyName)`
- `void fireVetoableChange(String propertyName, Object oldValue, Object newValue)`

Another annotation, @Listener, helps you register `PropertyChangeListeners` without so much effort. The following code

    import griffon.transform.PropertyListener
    import groovy.beans.Bindable@PropertyListener(snoopAll)
    class MyModel {
        def controller
        @Bindable String name    @Bindable
        @PropertyListener({controller.someAction(it)})
        String lastname    def snoopAll = { evt -> … }
    }

is equivalent to this one

    import groovy.beans.Bindable
    import java.beans.PropertyChangeListenerclass MyModel {
        def controller
        @Bindable String name
        @Bindable String lastname    def snoopAll = { evt -> … }    MyModel() {
            addPropertyChangeListener(snoopAll as PropertyChangeListener)
            addPropertyChangeListener('lastname', {
                controller.someAction(it)
            } as PropertyChangeListener)
        }
    }

@PropertyListener accepts the following values

- in-place definition of a closure
- reference of a closure property defined in the same class
- a List of any of the previous two