zhubert

a programming blog

Batman.js and Rails Part 3, Views

Last time, we quickly setup our app’s models and controllers…noting that they looked very similar to their server-side brethren.

Now let’s get some views…binding is done via HTML5 data- attributes, which is nice for your designer friends:

app/assets/javascripts/batman/views/posts/_post.html.haml
1
2
3
4
5
6
.well
  %h2
    %a{"data-bind" => "post.title", "data-route" => "routes.posts[post]"}
  %p{"data-bind" => "post.content"}
  %p.details-link
    %a.btn{"data-route" => "routes.posts[post]"} View details ยป

So the above is a partial (but you already knew that by convention), that has examples of binding (model changes forces view update) and the Named Routing syntax of Batman. Makes sense.

app/assets/javascripts/batman/views/posts/index.html.haml
1
2
3
4
5
6
%a.btn.btn-primary{"data-route" => 'routes.posts.new'} New Post
.row
  #content.span12
    #posts
      %div{"data-foreach-post" => "posts"}
        .post{"data-partial" => "posts/_post"}

Check out how you iterate over “enumerables” and include partials.

app/assets/javascripts/batman/views/posts/edit.html.haml
1
2
3
4
#edit-post.row
  #content.span16
    %form#edit_post.edit_post{"accept-charset" => "UTF-8", "data-event-submit" => "update", "data-formfor-post" => "post"}
      %div{"data-partial" => "posts/_form"}

Edit view includes a _form partial and wires the submit button to a particular controller action.

app/assets/javascripts/batman/views/posts/new.html.haml
1
2
3
4
#new-post.row
  #content.span16
    %form#new_post.new_post{"accept-charset" => "UTF-8", "data-event-submit" => "create", "data-formfor-post" => "post"}
      %div{"data-partial" => "posts/_form"}

New is the same as edit with some different classes and event.

app/assets/javascripts/batman/views/posts/show.html.haml
1
2
3
4
5
6
7
8
.page-header
  %h1{"data-bind" => "post.title"}
.hero-unit
  %p{"data-bind" => "post.content"}
.well
  %a.btn.btn-primary{"data-route" => 'routes.posts[post].edit'}Edit
  %a.btn{'data-route' => 'routes.posts'}Back
  %a.btn.destroy.btn-danger{"data-event-click" => 'destroy'} Destroy

Show is obvious. The destroy button isn’t immediately obvious, but the Core team didn’t like it routable so they suggest an event click. Works for me.

app/assets/javascripts/batman/views/posts/_form.html.haml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
%fieldset
  %legend
    %span{"data-hideif" => "post.id"} New Post
    %span{"data-showif" => "post.id"} Edit Post
  #error-explanation.alert-message.block-message.error{"data-showif" => "post.errors.length"}
    %p
      %strong
        %span{"data-bind" => "post.errors.length"}
        %span{"data-bind" => "'error' | pluralize post.errors.length"}
        prevented this post from being created:
    %ul
      %li{"data-bind" => "error.message", "data-foreach-error" => "post.errors"}
  .clearfix{"data-addclass-error" => 'post.errors.title.length'}
    %label{:for => "post_title"} Title
    .input
      %input#post_title.span8{"data-bind" => "post.title", :name => "post[title]", :size => "30", :type => "text"}
%fieldset
  .clearfix{"data-addclass-error" => 'post.errors.content.length'}
    %label{:for => "post_content"} Description
    .input
      %textarea#post_content.span8{:cols => "40", "data-bind" => "post.content", :name => "post[content]", :rows => "20"}
.actions
  %input.btn.btn-primary{:name => "commit", :type => "submit", :value => "Submit"}
    %a.btn{'data-route' => 'Post'} Cancel

Finally, the form partial has some logic to make the validation errors show up and so on. We also see some of the conditionals, pretty neat.

Pause for a second. The basic CRUD app is done. Fastest time to this stage of any framework I’ve looked at (I was timing productivity both in learning the frameworks from scratch and production of form crud). While figuring out how to do this took a much longer time, if you are following along I bet you got to this point under 30 minutes.

That’s pretty quick!

Next time, associations.

PS - And if you want it to look pretty, here’s the SASS I’m using:

app/assets/stylesheets/main.css.scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Place all the styles related to the posts controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: sass-lang.com/
// Set the correct sprite paths
$iconSpritePath: image-path('glyphicons-halflings.png');
$iconWhiteSpritePath: image-path('glyphicons-halflings-white.png');

//$navbarBackground: #555;
//$navbarBackgroundHighlight: #888;
//$navbarText: #eee;
//$navbarLinkColor: #eee;

@import "bootstrap";

body { padding-top: 40px; }

@import "bootstrap-responsive";

.navbar .brand {
  //color: #FAFFB8;
}

// Place all the styles related to the memories controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: sass-lang.com/

h1, h2, h3, h4, h5, h6, p, div {
  font-family: museo-slab, sans-serif;
}
html, body {
  background-color: #eee;
}

.container > footer p {
  text-align: center; /* center align it with the container */
}

/* The white background content wrapper */
.content {
  background-color: #fff;
  padding: 20px;
  margin: 0 -20px; /* negative indent the amount of the padding to maintain the grid system */
  -webkit-border-radius: 0 0 6px 6px;
     -moz-border-radius: 0 0 6px 6px;
          border-radius: 0 0 6px 6px;
  -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.15);
     -moz-box-shadow: 0 1px 2px rgba(0,0,0,.15);
          box-shadow: 0 1px 2px rgba(0,0,0,.15);
}

.notice {
    border: #444447 1px solid;
    padding: 10px;
    margin: 10px 0;
}

#error-explanation ul {
    margin: 10px 15px;
}
.error {
    border: 1px solid #c87872;
    padding: 10px;
    margin: 10px 0;
}

#posts {
  list-style-type: none;
}

Posted by Zack Hubert batmanjs, rails

Tweet

« Batman.js and Rails Part 2, Batman Install Batman.js and Rails Part 4, Associations »

Comments

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.