Bambi is a lightweight MVVM add-on for Vaadin web applications. Bambi uses a declarative style annotation-driven approach to UI binding. The framework attempts to adhere to basic MVVM principles and allows users to develop expressive UI with highly testable view models. One of the primary design goals of the Bambi framework is to enable the creation of minimalist, and highly readable code whilst not impeding the ability to deliver rich client user interfaces.
The overall structure borrows heavily from existing MVC/MVVM frameworks, including:
Bambi-MVVM uses Travis CI for continuous integration.
This add-on is made available via the official Vaadin add-on directory using the following link: https://vaadin.com/directory#addon/bambi-mvvm.
Alternatively see the releases section or checkout the source code for yourself.
- Java 5
- Maven 2.2
- A working internet connection
The project-name add-on project can be imported in any IDE that supports Maven.
- Compile and install the entire project:
`mvn install`
- Start the built-in Jetty web server:
`cd demo`
`mvn jetty:run`
- Open your favorite web browser and point it to:
http://localhost:8080/demo/
- Generate the manual:
`cd manual`
`mvn docbkx:generate-html`
- Open the file manual/target/docbkx/html/manual.html in your favorite web browser.
- Run the following command:
`mvn package assembly:assembly`
The following table contains a list of currently supported Bambi MVVM annotations:
Annotations | Description |
---|---|
@View | Applied to a view class that shall be bound to a view model. |
@PropertyBound | Applied to any UI element that implements the Property.Viewer interface (e.g. TextField ). Binds the element to a corresponding property declared in the view model. |
@ItemBound | Applied to any UI element that implements the Item.Viewer interface (e.g. Form ). Binds the element to a corresponding Item declared in the view model. |
@ContainerBound | Applied to any UI element that implements the Container.Viewer interface (e.g. Table ). Binds the element to a corresponding Container declared in the view model. |
@ActionBound | Applied to Button elements in the UI. Binds the button click event to a method in the corresponding view model. |
@EventBound | Applied to any UI Component . Binds a specified event to a corresponding event handler method in the corresponding view model. |
@ValueChangeBound | Applied to any UI element that implements the ValueChangeListener interface (e.g. TextField , Table , etc). Binds the value change event to a method in the corresponding view model. |
@View(model = AddressBookViewModel.class)
public class AddressBookView extends CustomComponent implements Handler {
private static final long serialVersionUID = 1L;
@ActionBound(to = "addAddress")
private final Button addButton = new Button("New Address");
@ActionBound(to = "removeAddress")
private final Button removeButton = new Button("Remove Address");
@PropertyBound(to = "selected")
private final AddressBookForm form = new AddressBookForm();
@ContainerBound(to = "addresses", columns = { NAME_PROPERTY,
SURNAME_PROPERTY, LINE1_PROPERTY, LINE2_PROPERTY, CITY_PROPERTY,
STATE_PROPERTY, AREACODE_PROPERTY, COUNTRY_PROPERTY })
@ValueChangeBound(to = "selectAddress")
private final Table table = new Table();
private final Action commitAction = new ShortcutAction("ENTER",
ShortcutAction.KeyCode.ENTER, null);
...
}
public class AddressBookViewModel implements Serializable {
private static final long serialVersionUID = 1L;
public final Container addresses = new BeanItemContainer<Address>(Address.class);
public final ObjectProperty<BeanItem> selected = new ObjectProperty<BeanItem>(null, BeanItem.class);
public void selectAddress(Property.ValueChangeEvent event) {
Table table = (Table)event.getProperty();
Item selectedItem = table.getItem(table.getValue());
selected.setValue(selectedItem);
}
public void addAddress(Button.ClickEvent event) {
Address newAddress = new Address();
Item item = addresses.addItem(newAddress);
selected.setValue(item);
event.getComponent().getWindow().showNotification("Address Added",TYPE_HUMANIZED_MESSAGE);
}
public void removeAddress(Button.ClickEvent event) {
BeanItem item = (BeanItem)selected.getValue();
Address address = (Address)item.getBean();
if(addresses.removeItem(address)) {
event.getComponent().getWindow().showNotification("Address Removed", TYPE_HUMANIZED_MESSAGE);
}
}
}
public class AddressBook extends Application {
private static final long serialVersionUID = 1L;
private Window window;
/** {@inheritDoc} */
@Override
public void init() {
window = new Window("Bambi Demo Application - Address Book");
ViewContainer<AddressBookView> view = new AnnotatedViewFactory().materialize(AddressBookView.class);
window.setContent(view);
setMainWindow(window);
}
}
Bambi is released under Apache 2.0 license.
Copyright 2012 Michael Fazio
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.