This maps a new url create to our app. When the user visits that
url Ember.js will automatically render the create template in the
application template’s outlet.
The CreateController contains the name property and a save function. The
name property is bound to the text box in the create view.
The save function will be called once the user submits the form.
To create a new kitten record on the client side we use createRecord.
Ember Data’s save function returns a promise. This promise is
resolved when the server responses successfully. When that happens we
want to transition to our list of kittens and empty out clear out the
fields input.
We need to declare two new types for our server side kittens. The first
Kitten is a simple struct that has our three fields: id, name, and
picture.
The second structure serves as our external data structure. Ember Data
expects single Kittens to be wrapped in a named json object. For example:
single kitten response
1
{"kitten":{"id":1,"name":"Ben"}}
Ember will also send Kittens to the server wrapped in this style request.
server.go
1234567891011121314151617181920212223
funcCreateKittenHandler(whttp.ResponseWriter,r*http.Request){// Parse the incoming kitten from the request bodyvarkittenJSONKittenJSONerr:=json.NewDecoder(r.Body).Decode(&kittenJSON)iferr!=nil{panic(err)}// Grab the kitten and set some dummy datakitten:=kittenJSON.Kittenkitten.Id=5kitten.Picture="http://placekitten.com/300/200"// Serialize the modified kitten to JSONj,err:=json.Marshal(KittenJSON{Kitten:kitten})iferr!=nil{panic(err)}// Write the responsew.Header().Set("Content-Type","application/json")w.Write(j)}
To create a kitten we need to define a function that will handle the
route.
In order to gain access to the incoming json request from Ember Data we
need to decode the request’s body. To do this we use a json.Decoder.
We new up a decoder and decode the payload into an instance of
KittenJSON. The decoder will populate all the data for us according
to the struct’s definition.
Because we want to get this example up and running as quickly as
possible I am just manually setting an Id and Picture. The Name property
will be set from the incoming json.
We then need to return a response to the client so we serialize our
kitten back into a KittenJSON type and write it to the response
writer.
server.go
1234
funcmain(){// ... omited rest of functionr.HandleFunc("/api/kittens",CreateKittenHandler).Methods("POST")}
We need to tell the server when to create a kitten. The create behavior
for Ember Data is a POST to the index end point. The Gorilla Mux makes
this easy by allowing us to specify the method.
All the wiring complete
All the wiring for this evolution of the app is now complete. We can
click the create link, fill out the form, and show the user that we
created a kitten.
In Memory Storage
Now the we can create kittens let’s rig up an in memory store to make
the application feel slightly more complete.
Today we embark on a magical jounry of Gophers and Tomsters. In open source the projects with the cutest mascots always gain traction!
With the power of the internets cutest mascots combine we will create
the most basic crud app to help you hit the ground running with Ember.js
and Go.
Up and Running
The first part of any Ember project is to get the basic up and running.
Since this is a super basic example we are just going to wire up a Go
server to serve our static assets.
We now have two files. An index.html file with hello world in it and a
sever.go file that will serve statis assets out of the public directory.
To run this all you need to do is
1
go run server.go
You should be able to visit http://localhost:8080 and see hello world in
your browser.
Personally I feel uneasy that we are not giving ourselves some
feedback of what the program is doing so let’s add some logging.
server.go
1234567891011121314
packagemainimport("net/http""log")funcmain(){log.Println("Starting Server")http.Handle("/",http.FileServer(http.Dir("./public/")))log.Println("Listening on 8080")http.ListenAndServe(":8080",nil)}
That makes me feel much better.
Setup Ember
Now that we have a basic http server we can setup our Ember environment.
I have included a script that will grab jQuery, Handlebars, and Ember
for your. These are all the dependencies that you need to get the
project up and running.
Now we can actually create our ember application. The canonical example
name space is App, but you can use any name that you would like.
This line of code bootstraps your Ember application. It will
automatically run once the page is loaded.
Don’t forget to include the new file in our index.html file after all
the lib scripts.
1
<script src="js/app.js"></script>
When you view your application in the browser you should see the
following output in your developer console. If you do not see this then
something is broken. Make sure that all your files are loading
correctly and that they are in the correct order.
The Gorilla mux provides a ton of wonderful functionality that we will
take advantage of later. For now a simple GET endpoint is all we need to
move this application forward.
I prefer to have my api endpoint under an /api name space. This is not a
requirement, but a personal preference.
Ember Data expects a very particular response. You want to wrap a
collection response with the plural of the model name. So in our case the
root should be kittens and the value of kittens should be an array
of kitten objects.
The first thing we need to do is create a data store. We also need to
tell the store’s adapter that we want to namespace ajax calls under the
api namespace.
Ember will automatically route to the index route of an application. We
can alter the behavior of the index by defining an App.IndexRoute.
This is where we can hook into the model function and return our
kittens.
We modified the application template and added a new index template.
The application template now has an outlet. This is where ember will
insert the index template or any other template defined by the current
route.
In the index template we use the each helper to loop over all the
kittens and output them with some basic markup.
In order to display the image we need to use the bindAttr helper.
This will ensure that the src attribute is bound to the models picture
property.
End of part 1
It took a bit of work to get this example up and running, but things
assuming you were able to follow along you should have a fully
integrated ember.js app with a go back end.
In the next part we will focus on adding new pages and some editing.
Happy Embering and Gophering :)
Full Source
The full source code to this example can be found on my github account.
First we declare our struct. For this example we are using only a
single field which is a string. We also need to define our collection
type so that we can satisfy the sort.Interface.
The first method Len needs to return how many elements are in our
collection. The built-in len function will work beautifully for this.
The second method is where we need to figure out which element comes
before. For this example we just do a basic string comparison which
will give us an ascending alphabetical sort order. If we wanted to
sort descending we could just flip the < operator to >.
The last method actually performs the work of shuffling elements
around. Go’s multiple assignment makes it easy to swap the values
without having to explicitly declare a temporary variable.
The Countries type now provides all the methods to satisfy the
sort.Interface interface.
Middleman one of my favorite ways to build
single page web applications these days. It is a simple static site
generator that uses Sprokets. It is a really
wonderful way to develop small applications.
This post is going to walk you through the process of setting up all the
dependencies of an Ember.js App.
There are some builders and gems floating around these days. For the
most part they fall behind Ember.js development too quickly. This ends
up meaning that you spend more fixing dependencies than you do developing
your app.
This line of code tells our template compiler to strip out the
template path from our file names. So any file with the path
app/templates/template.hbs will be converted to template correctly.
This is the project layout that I prefer to use. All application code
gets tucked away in the app directory and all external libraries gets
tucked away in vendor.
Also note that I build these two files separately. This is because the
vendor file changes much less frequently than the app.js file. This means
that the browser only has to update the vendor.js when we change a
dependency, not when we change a line of application code.
The require comments are part of sprokets. require_self includes the
current file. require_tree includes all the files alphabetically in
the directory specified.
Every single month for the past ten years I have been looking forward to
Global Trance Grooves.
For as long as I can remember I have been driving with the windows down
or writing code while listening to the monthly show. It is one of my
favorite rituals.
I have never been disappointed by the content on John’s show. He has
honed the skill of picking the best DJs and producers to highlight and
promote. It is not his raw talent that makes this show incredible, it
is his tenacious desire to spread the music he loves.
When I talk about trance music, John 00 Flemming is what I am referring
to. The style he promotes represents the sound that I love. Deep,
dark, and hypnotic.
This April marked the 10 year anniversary of Global Trance Grooves.
John celebrated by putting together an absolutely stunning line up of
artists.
If you missed the live broadcast you can download all the sets on
soundcloud. Also I have included the link for John’s 2010 essential mix.
It is a favorite of mine.
<!-- note, I am only using single {} because octopress eats handlebars tags --><ulclass="sortable">{#each item in controller}
<liclass="item"data-id="{unbound item.id}"><b>{item.idx}</b> {item.id}
</li>{/each}
</ul>
In order to bind the sortable plug-in to the DOM we use the
didInsertElement function. This function is called when the view’s
element is in the DOM and ready to be manipulated.
We call sortable on the list view that has the CSS class .sortable.
This will bind jQuery UI’s sortable plug-in to our DOM element.
The only function we have to implement is the update function. This
function is called when the sortable plug-in has finished sorting and the
DOM is updated.
What we want to do in the update method is create an index of model ids
with their new sort position. We can accomplish that by looping over the
items in the list, grabbing the data-id and assigning it the value of the
index.
Once we have created an index we need to cancel the sort. This is
because we are going to update the model to reflect the new sort order.
I was asked the question about why programmers dislike certain languages
and frameworks. The question was made after I was finished talking
about local opportunities to a new a friend. My comment was that “I would
apply to work there, but they are a PHP shop.”
PHP is self is not bad, nor are the things that any skilled programmer
can build with it. In fact it is a wonderful tool. It is designed to
fit a majority of the web out there. It is battle hardened and
delivers on customer value.
The real problem is that as a programmer it is my job to keep my tools
sharp, fresh, and organized. Exactly like a chef will maintain their
knives and cookbooks.
This entire blog is filled up with code that I have not been paid to
write. It is this kind of effort that I am willing to do to maintain and
improve my skill set.
Keeping your skill level up as a programmer is a free time endeavor. It
is an incredibly rare position where you can freely invest time on the
job to learn and fail. If you have one of these mythical super awesome
jobs, please do contact me :)
It is that fact is why PHP is not in my skill set. It is not a tool that
I am willing to invest my personal time to grow and maintain.
Back to my pretentious sounding comment that started this post. I would
have absolutely zero issue working for a shop where php was the primary
language.
It would have to be such an incredible opportunity that I am willing to
invest 100% of my free time into keeping that skill honed. I’m pretty
sure the only opportunity on the planet that meets those requirements is
Facebook, with a 6 figure starting salary, and an incredible team.
Even so, I would still give up a chunk of my salary to work with tools that I
love.
Modal views seem to be a source of pain in the ember world. Not all
applications treat a modal state the same. Some applications consider a
modal a new route, others treat it as a non routed state.
For most crud modals I prefer to have them not route based.
This is due to the fact that modal edit/create dialogs tend to be a
shorter version of the form than their routed counter parts.
Generally this is my short list of requirements for modals.
Server must acknowledge success or failure before the modal can close
Animate open and close
These are the genral requirements that I deal with all the time. Things
like jquery ui modals and bootstrap modals are wonderful for most
things, but as soon as your need to control the life cycle or change the
close triggers they become overly complex.
After all a modal is just a div with a backdrop, it is not rocket surgery.
Let’s dive into how to make this happen with ember.
We can start by defining how we want to open and close our modal. The
openModal function takes the name of a modal view i.e. widgets.modal
and renders it into the application’s outlet named modal.
The closeModal function uses a application wide function
App.animateModalClose() which returns a promise that is resolved when
the modal is finished animating. Then we simply remove the modal from
the outlet by rendering an empty template into the outlet.
The edit event will be triggered from a handlebars template with a
widget argument.
The WidgetsModalController#edit function takes a record and listens
for the didUpdate model life cycle event. This event is triggered once
the server acknowledges the model was updated. Then we send the
closeModal event which will be handled by the ApplicationRoute.
When we send the openModal event the ApplictionRoute will handle the
event. Ember will then render the widgets.modal template with the
WigetsModelController.
Overall I do like the design of the modal controller. It only knows
about the model’s life cycle and that there is something in the
application that will handle the closeModal event. This seems like
just enough responsibility for a controller to have. A parallel would
be a rails controller that updates a modal and sets the flash message.
Animating Open and Close
modal_view.js
123456789
App.ModalView=Em.View.extend({// the yeild is missing a pair of { }.// octpress likes to interpret them as liquid tags :(layout:Em.Handlebars.compile("{yield}<div class=modal-backdrop></div>"),didInsertElement:function(){App.animateModalOpen();}});
This the basic modal view. All it does is set up a layout with the
modal backdrop and call our animation method once the element is
inserted into the dom.
The animation methods should be asynchronous. To make sure that we know
when the modal is done animating we simply resolve a promise after some
predefined duration. We could also do the animation via jQuery and not
have to change the external interface.
fin
This is one way of handling modal views.
Ember gives you a lot of options. Your going to have to pick the ones
that work best for your application.
How are you handling modals in your applications? Can you share a
complete example? <3
I have been using this set of headphones every single day for around six
months. So far the only thing to show any sign of wear are the pillow
like velour ear cushions.
The more I use these headphones the more comfortable they become. When
I first slipped them on they were a very tight. To solve this problem I
left them on a one gallon water jug over night for a week. This
loosened up the headphones enough to be comfortable and still fit well.
Overall the sound quality is superb. Which can be unfortunate at times
since the majority of my incoming music is 128k mp3s. I quickly noticed
how bad some of my favorite tracks sounded.
The output of these headphones is calibrated towards the low end. This
is exactly what I was looking for in a set of headphones. They do not
artificially amplify the low end frequencies, but rather highlight them
in a pleasant way. If your looking for super bass thumpy headphones
keep looking, these are not for you.
One very important note: not for the office. The open back design
leaks sound so you will annoy your coworkers quickly.
I have not found an overwhelming reason to go out and buy an external
amplifier for these cans yet. My MacBook pro powers them quite well.
However I mostly listen to electronic music these days so YMMV. If I
ever get the chance to borrow one I will certainly follow up on this
note.
Headphones are a very important part of my life. I spend a lot of time
thinking and coding in the flow of a long trance set. I am very happy
with this set. They are comfortable, sound wonderful, and well
designed. If these break for any reason what so ever, I would not
hesitate to purchase them again.