Source RavenDbBreeze sample
I started taking much more interest in SPA development, and combination from the title has been gaining a lot of popularity lately, so i decided to give it a go. There are a few critical questions that i needed answered and since there are rather new technologies, the information is quite scattered.
I looked at a bunch of technologies, stacks, trying to get a hold of the best solution. Eventually i decided on doing some forking on the NoDB sample project from Breezejs and see if i can bend it to my will. So here is my WTFAQ while i was delving deep into the problem. And there’s gonna be a nice source code at the end of all this:).
So which nuget package should i get for quick and easy development?
Just one, and that’s RavenDB.Embedded. That should probably get you started.
What about starting framework, which one to choose?
Well, i would definitely go with Hot towel, it’s beautifully set up. But some other projects and templates i recommend are Twitter Bootstrap MVC 4 nuget (for authentication and templates) and NoDB sample from breeze site. Also, have a look at Edmunds sample for a 3rd party rest consumption with breeze.
So what are some of the gotchas?
Well, so far, i ran into one particularly annoying problem, and it concerns routing. It’s problematic if you’d like to add an outside link through mapNav function in durandal (which probably isn’t even meant for that). Trouble is, the routing on IE and Chrome behave differently (so the link will work on IE but not on Chrome). Also be prepared to learn alot about binding, modules etc. if you haven’t already. But ultimately, it’s a pretty sane solution for a Javascript:).
Is Breeze suited for storing documents, i.e. complex structures and using with NoSql and RavenDB?
The short answer is yes, and what’s even better, from what i’ve seen from breeze it’s a surprisnigly open, versatile and convenient framework for data manipulation. It really is extremely nice to work with, especially for seasoned silverlight veteran:). Now there are some stuff that need to be hand coded, but i think that it’s only a matter of time until a proper metadata provider is made for it. Other than that, i think i found my favourite solution for data manipulation on client side.
I have problems with ComplexType arrays, how do you set that up?
It’s a bit tricky for a beginner, but it’s mostly because of the lack of documentation. But once you set it all up it’s pretty straightforward. Have a look at the rearranged TodoItem, especially files todo.model.js and todo.datacontext.js. TodoItem is now a complexType, which gets stored in a TodoList document.
I also added a SaveChanges button, and to have it work properly you will have to comment out line 15 in todo.datacontext.js (//configureManagerToSaveModifiedItemImmediately();)
How about some code?
So let’s go over a few use cases. I reworked the NoDB sample from breeze website to use RavenDB and Complextype for Todos. Firstly, the metadata setup, i’ll show an excerpt (todo.model.js)
function addTodoItemType(store) { store.addEntityType({ shortName: "TodoItem", namespace: "NoDb.Models", isComplexType: true, dataProperties: { id: { dataType: DataType.String, isNullable: false }, title: { dataType: DataType.String, maxLength: 30, isNullable: false, validators: [ Validator.required(), Validator.maxLength( {maxLength: 30})] // Add client-side validation to 'title' }, isDone: { dataType: DataType.Boolean, isNullable: false }, todoListId: { dataType: DataType.Int32, isNullable: false }, } }); function addTodoListType(store) { store.addEntityType({ shortName: "TodoList", namespace: "NoDb.Models", autoGeneratedKeyType: AutoGeneratedKeyType.Identity, dataProperties: { id: { dataType: DataType.String, isNullable: false, isPartOfKey: true }, title: { dataType: DataType.String, maxLength: 30, isNullable: false }, todos: { dataType: DataType.ComplexType, complexTypeName:"TodoItem:#NoDb.Models", isScalar: false} }, });
The important bits are the property isComplexType on TodoItem and the definition of todos property on TodoList. todos is defined as an array of TodoItems (isScalar:false and complexTypeName).
The next example will show how we add a new item to TodoList (todo.model.js)
TodoList.prototype.addTodo = function () { if (this.newTodoTitle()) { var todoItem = datacontext.createTodoItem( { title: this.newTodoTitle(), id: DataType.Guid.getNext() }); this.todos.push(todoItem); this.newTodoTitle(""); } };
I decided to keep the id property for items, so i’m setting it up to guid. Additionally, i changed type of id across the board from int to string (much friendlier for Raven). There is a method createTodoItem which is defined in todo.datacontext.js and this is the way you create complexobjects:
function createTodoItem(initialValues) { return manager.metadataStore.getEntityType("TodoItem").createInstance(initialValues); }
So instead of using new keyword, this way we get a nice observable object ready for databinding.
On the server-side i integrated TodoContext with RavenDb, it’s pretty standard affair. Note that while modifiying TodoItem, i am actually sending a whole list over the wire, which I find convenient, the list can be completely overwritten.
The code is attached to this post, so i think it will speak for itself a lot. If you have any trouble, leave a comment.
Cheers!
Leave a Comment