If you are new to Errai, the quickest way to get started is via the archetypes described in our Getting Started guide.
New in 2.1
We're calling these new features in 2.1 "preview" because we want a chance to incorporate your feedback before we lock down the APIs in 3.0. We crave your input: share your use cases, feature requests, and of course pull requests.
Client-Side JPA
@NamedQueries ({
@NamedQuery(name="allAlbums",
query="SELECT a FROM Album a ORDER BY a.releaseDate, a.artist"),
@NamedQuery(name="albumByName",
query="SELECT a FROM Album a WHERE a.name LIKE :name")
})
@Entity
public class Album {
@GeneratedValue
@Id
private Long id;
private String name;
@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})
private Artist artist;
private Date releaseDate;
private Format format;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
...
@Override
public String toString() {
return "Album [id=" + id + ", name=" + name
+ ", artist=" + (artist == null ? "null" : artist.getName())
+ ", format=" + format
+ ", releaseDate=" + releaseDate + "]";
}
}
Of course, this code does the same thing on the client as it would on the server:
@Inject EntityManager em;
public void createExampleAlbum() {
Artist samNDave = new Artist();
samNDave.setName("Sam & Dave");
samNDave.addGenre(new Genre("Rock"));
samNDave.addGenre(new Genre("Soul"));
samNDave.addGenre(new Genre("R&B"));
Album album = new Album();
album.setArtist(samNDave);
album.setFormat(Format.LP);
em.persist(album);
em.flush();
}
public List<Album> fetchAlbums(String nameContains) {
TypedQuery<Album> query = em.createNamedQuery("albumByName", Album.class);
query.setParameter("name", "%" + nameContains + "%");
return query.getResultList();
}
samNDave.setName("Sam & Dave");
samNDave.addGenre(new Genre("Rock"));
samNDave.addGenre(new Genre("Soul"));
samNDave.addGenre(new Genre("R&B"));
album.setArtist(samNDave);
album.setFormat(Format.LP);
album.setName("Hold On, I'm Comin'");
album.setReleaseDate(new Date(-121114800000L));em.persist(album);
em.flush();
}
public List<Album> fetchAlbums(String nameContains) {
TypedQuery<Album> query = em.createNamedQuery("albumByName", Album.class);
query.setParameter("name", "%" + nameContains + "%");
return query.getResultList();
}
Get your hands dirty by playing with the demo, which you can find on GitHub.
ErraiUI Templates
In Errai 2.1, we're adding a new option to the mix: Errai UI. Errai UI gives you declarative layout through templates that are valid HTML 5 documents, paired with Java classes that imbue behaviour into them. Of course, you get compile-time checks to make sure everything lines up properly. We want to help you avoid unpleasant surprises at runtime!
Here's an Errai UI template:
<!DOCTYPE html>
<div>
<label for=itemName>Name:</label>
<input id=itemName type=text data-field=name>
<br>
<label for=itemDept>Department:</label>
<input id=itemDept type=text data-field=department>
<br>
<label for=itemComments>Notes:</label>
<input id=itemComments type=text data-field=comment>
<br>
<button class=btn data-field=saveButton>Save</button>
</div>
The only special bits are the data-field attributes. These line up with field names in the companion Java class, like this:
@Templated
public class ItemForm extends Composite {
@Inject @DataField private TextBox name;
@Inject @DataField private TextBox comment;
@Inject @DataField private TextBox department;
@Inject @DataField private Button saveButton;
public void grabKeyboardFocus() {
name.setFocus(true);
}
@EventHandler("saveButton")
public void onSaveButtonClicked(ClickEvent event) {
// this method will be called for each click event on saveButton
}
}
To handle events, simply annotate a method with @EventHandler("DataFieldName"). The method should take an argument of the event type you want to receive. Errai UI will ensure the source node sinks the appropriate events, and it will deliver them to your method each time they happen.
To learn more, check out the ErraiUI demo, and also read through Errai UI's reference guide.
But wait! There's more!
There are two more new Errai modules that go great with Errai UI: data binding and navigation.
Model-View Data Binding
Errai Data Binding lets you bind property values in your model objects to widgets in your UI.
To make a model object amenable to having its properties bound, annotate it with @Bindable:
@Bindable
public class Employee {
private int id;
private String name;
private Integer age;
private boolean active;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
public boolean isActive() { return active; }
public void setActive(boolean active) { this.active = active; }
}
Then to establish data bindings to UI widgets, use the fluent configuration API:
public class EmployeeForm {
private final TextBox nameTextBox = new TextBox();
private final TextBox ageTextBox = new TextBox();
private final CheckBox activeCheckBox = new CheckBox();
private Employee employee;
@PostConstruct
public void init() {
employee = DataBinder.forType(Employee.class)
.bind(nameTextBox, "name")
.bind(ageTextBox, "age")
.bind(activeCheckBox, "active")
.getModel();
}
}
Declarative Data Binding
When Errai Data Binding is used together with Errai UI templates, you can skip the fluent API and simply declare "auto-bindings." Going back to the ItemForm example:
...
@Inject @AutoBound private DataBinder<Item> itemBinder;
@Inject @Bound @DataField private TextBox name;
@Inject @Bound @DataField private TextBox comment;
...
By injecting an @AutoBound DataBinder and adding the @Bound annotations on the widgets, we get a declarative approach to data binding. With the above code snippet in place, it will always be true that itemBinder.getModel().getName().equals(name.getText()).
Errai data binding also allows custom converters, wrapping existing model objects, and more. See the reference guide for all the juicy details!
"Multi-Page" Navigation
The third new UI-related feature in 2.1 is Errai Navigation. Errai Navigation adds a decentralized, declarative configuration mechanism to GWT's built-in History facility. This allows back-button and forward-button navigation, plus bookmarkable locations within your app. And since the configuration is declarative, it even produces navigation flow graphs like this at compile time:
The navigation system simply manages the contents of a panel (a div element in the DOM): based on what comes after the # in the location bar, the contents of that div change. Typically, in your app's entry point, you would add that panel to a large, central region of the document. Headers, footers, and sidebars can remain outside of this div, which allows them to stay in place when the user navigates between pages.
As an example, if you want the URL http://example/my-app/host-page.html#FunPage to cause the page body to contain an instance of your FunPage widget, you would do the following:
@Page
public class FunPage extends Widget {
// whatever Widgety things you want to do
}
Pages are CDI beans, and the navigation obtains instances from the client-side bean manager when needed. So the above implicit-scoped bean would be newly instantiated each time the browser's URL bar changes to http://example/my-app/host-page.html#FunPage. If you'd prefer one instance of FunPage to hang around for the life of the app (simply appearing and disappearing based on the current URL fragment,) just annotate it with @ApplicationScoped.
But what good are pages without links between them? To make links between pages, inject TransitionTo instances like so:
@Page
public class FunPage extends Widget {
@Inject TransitionTo<UltraFunPage> upgradeLink;
@Inject TransitionTo<WelcomePage> quitLink;
@Inject TransitionTo<SillyPage> sillinessEnsues;
public void onQuitButtonClick(ClickEvent e) {
quitLink.go();
}
// whatever Widgety things you want to do
}
These links make up the arrows in the navigation graph that's produced at compile time. The type parameter controls the widget (CDI bean) type that provides the page contents, and the field names are the label text on the arrows.
Of course it goes without saying that Errai Navigation goes great with Errai UI templates: a @Templated widget can also be a @Page.
Improved Since 2.0
Client-side Remote Call Interceptors (JAX-RS and RPC)
Sometimes you need a chance to tweak a request just before it's sent to the server. For example, maybe you need to add special authentication headers to certain REST requests. Or maybe you want to short-circuit requests when you already have locally-cached data. Previously, you would have had to give up on the typesafe Errai JAX-RS Caller<T> interface for those requests, and fall back to RequestBuilder.
Well, starting in Errai 2.1, you can intercept, inspect, modify, and even cancel any Errai JAX-RS and Errai RPC request. See the documentation for the details and example code.
GWT 2.5 Compatibility
In Errai 3.0, we do plan to bump up the minimum requirement to GWT 2.5, so get testing!
Code-and-Refresh: Better Than Ever
Additionally, the dynamic (server-side) marshalling system in Errai 2.1 is now run through the same set of tests as the statically-compiled marshallers. This means you can stick to dynamic marshalling at development time, with two big advantages: firstly, it makes dev mode setup simpler (especially when using an external web server); secondly, it behaves well in conjunction with server-side hot reload products such as JRebel.
Errai Marshalling: Now Compatible with Jackson
The user guide has a section that details how to enable Jackson compatibility mode in the REST client.
Try it
Now that 2.1.0.RC2 is out in the wild, I hope you will take the time to test your Errai app with it. We hope to go final soon, so get those bug reports and pull requests in before it's too late!And if you're new to Errai, the quickest way from-zero-to-Errai is our Getting Started guide.
Happy hacking!
Hi errai team,
ReplyDeleteAll the added features impressed me a lot.
I looked at navigation sources and it does not seem that it is possible to pass parameters in a page transition setting them in the start page and extracting them in the destination page.
I can do that in gwtp and it is the only feature I really miss (if did not overlook something...).
I particularly like the template mechanism.
thanks a lot
ciao Francesco
I'm trying out Errai Jackson Integration... the docs are really limited. How can I configure a custom mapper ? What exactly do you mean with Jackson support ? How far does this support go ?
ReplyDeleteI'm very happy being Herpes free now. It was a sad incident that was announced to me after the check up in the hospital and I was diagnosed of HSV 2. I thank God now for using Dr.odey Abang to cure my virus. I'm not ashamed to say this because no virus of such can be detected in me. I'm Charlotte from Columbia. I thought about it many Times when I heard about this Herbal cures for Herpes. I was really happy when I came across blogs of comments of Doctors who run cures sicknesses and was comfortable to try Dr. Abang from patients testimony I came across here on my online page. I knew now they are real Africa herbalists who run cures for Herpes. There's every opportunity to be cure with natural herbs, because all medical prescriptions are derived from herbs and roots. Its really hard time living with Herpes on drugs which can't get you cure. I tried this and I can boost of myself now as a woman. I need to be loved not to lost, get your instant cure to all sicknesses from Dr, Odey Abang.
ReplyDeleteHe cures HSV,HPV,Cancer,low spam count and much more from the evidence I saw 💯 % sure no site effects with active immune booster
Email him for you cure
Odeyabangherbalhome@gmail.com
WhatsApp/calls
+2349015049094