Brad Olenick announced the new RIA/JS jQuery plugin at MIX11. This plugin wraps a RIA DomainService; adding events, change tracking, validation, and more. Brad’s presentation “Building Data-centric N-tier Applications with jQuery” demonstrates many of these features including shared validation, sorting, filtering, buffering, and change tracking.
The RIA/JS jQuery plug-in is based around a datasource. This datasource is used to link a RIA domain service to a collection of JavaScript objects. Events on this data source allow actions to be taken when items are added to or removed from collections as well as when an individual item is updated or marked deleted. This model also includes a distinction between server-side deletes and client-side deletes.
A bound datasource will listen to and automatically handle events on its collection. For example, if an item is added to the collection using $.push, the datasource will automatically handle the call back to the server. Optionally, changes to a datasource can be buffered. In this case, changes are accumulated until .commitChanges() or .revertChanges() is called.
Shared validation helps avoid the common scenario of separate server-side and client-side code for the same validation action. The plug-in serializes the RIA domain service validation attributes to the client so that the same validation rules are available for validation on the client as well.
We contacted Brad to ask him for some more details about these features -
InfoQ: Will it be possible to write custom validators that take advantage of shared validation?
Brad: By custom validators, do you mean validation logic that’s authored in C# and then serialized to the client?
We’ve talked about that a fair amount.
Mostly, we’ve thought about RIA/JS managing the async invocation of C#-authored validators in a RIA DomainService. The alternative of cross-compiling C# to JavaScript sounds dicey, mostly due to having to translate C# calls to .Net library methods (think “Int32.ToString()”) to equivalent JavaScript.
InfoQ: Are there any plans to allow more granular change buffering, such as at the event level? For example, instant inserts and buffered updates.
Brad: Yes, I’ve actually thought a lot about this, but I haven’t had the time to land a reasonable design. Right now, this granularity is decided at $.dataSource construction time, which doesn’t reach the scenario you’re talking about. I’ve thought about a more flexible mode that does implicit commit – but at a granularity controlled by the application. One scenario here is a JS click handler that wants to commit a number of related edits in a single transaction.
RIA/JS could have a programming model somewhat like System.Transactions.Transaction in .Net. Here, the JS app could pass a function to $.dataSource that applies the group edits. $.dataSource would change-track only for the duration of that function call and then commit.
The other scenario I have in mind – which is probably your “For example…” above – is where an HTML <form> can do its change-buffering in one or more RIA/JS entities (for “buffered updates” above) while the larger UI is implicitly committing edits (your “instant inserts” above).
I’m still thinking about this scenario. As things stand today, you can do this by using 2 distinct $.dataSource instances – one for the <form> and another for the larger UI. I feel we can improve upon this though.
InfoQ: WCF JQuery sounds like it would be a great base for a set of UI controls. Can we look forward to something along those lines?
Brad: The JavaScript and jQuery communities love to have choice here, and that’s why I’ve been focusing my energies on the jQuery “data model” as part of the jQuery UI’s Grid project.
If the jQuery team lands a well-designed data programming model, then – minimally – jQuery UI controls will work great with RIA/JS. It’s quite possible that other UI and UI control offerings will elect to layer on top of the jQuery data model, just as jQuery UI will. This will give developers who use RIA/JS even more choice here. I’d love to see developers who use RIA/JS have the ability to pick options like Wijmo, jQuery Mobile, KnockOut.js, etc. for their UI.
As for MS-provided UI controls specifically, that’s one of the options we’re considering in the context of giving WCF RIA and Windows AppFabric developers a great end-to-end development experience.
InfoQ: Can you tell us something about features planned for future releases?
Brad: We’re going to continue building RIA/JS features to roughly match those of the WCF RIA Services Silverlight client. You mentioned “custom validators” above, and that’s a good example. We’ll give apps the flexibility to do more than CUD, supporting custom invoke and update operations. We’re also going to invest in better VS integration and tooling.
Separately, we’re enabling RIA Services as an application pattern in Windows AppFabric. Developers who like RIA’s n-tier application pattern will have a great way to develop their app for the cloud and realize AppFabric benefits like better deployment, monitoring, management, etc..
Also, we’re going to add OData protocol support to RIA/JS and improve OData support in RIA DomainService. With this, developers will have more flexibility as to how they build services for their larger app (WCF RIA Services, WCF Web API, WCF Data Services).
InfoQ: Lastly, was there anything you would have liked to cover during MIX11 but couldn't due to time constraints?
Brad: One thing I couldn’t show was our support for data sources sharing the same underlying context of entities. This is useful when you have, for instance, one part of your app visualizing Customers and their Orders and, separately, another part visualizing Orders and OrderDetails. When the two data source in this scenarios share the same $().dataSource().dataContext(), the Order entities are shared and reflect updates through both data sources.
Another thing – of interest to JavaScript developers – is how developers can control the shape of data surfaced by $.dataSource. Some JavaScript developers may be accustomed to sending database rows or XML tree-shaped data items to the browser. Graphs of entities might be seen as being heavy or unfamiliar. $.dataSource() will expose graphs of entities only if the underlying service (the RIA DomainService presently) returns appropriate primary and foreign key metadata. As part of the design of their RIA DomainService, developers determine what primary/foreign key metadata to serialize to their JavaScript client. In the extreme, should a developer elect to send no key metadata, RIA/JS’s $.dataSource would expose simple data records with only scalar-typed field values.
A question that came up post-MIX was the code download size of RIA/JS. At present – and this hasn’t been a focus yet in development – our minified download size is < 50k. As a reference, jQuery Core is > 70k.
The following code sample by Brad illustrates two data sources sharing the same context:
// Constants var serviceUrl = "CustomersAndOrders.svc"; var customerID = 42; // Data var customers = [], orders = []; // Get single customer with ID == 42 $([ customers ]).dataSource({ serviceUrl: serviceUrl, queryName: "GetCustomers", filter: { property: "ID", value: customerID } }).refresh(); // Get orders for that customer $([ orders ]).dataSource({ serviceUrl: serviceUrl, queryName: "GetOrders", filter: { property: "CustomerID", value: customerID }, dataContext: $([ customers ]).dataContext() // These two data sources share the same cache of entities. }).refresh(); ... var customer = customers[0]; // Each order.Customer should match the customer we explicitly loaded. $.each(orders, function() { var order = this; assert(order.get_Customer() === customer); }); // Each order in customer.Orders should match an order we explicitly loaded. $.each(customer.get_Orders(), function() { var order = this; assert($.inArray(order, orders) >= 0); });