Last active
July 17, 2021 08:05
-
-
Save bhollis/8469859 to your computer and use it in GitHub Desktop.
A simple, made-up example of the code for a simple AngularJS blog viewer as a more detailed exploration of http://benhollis.net/blog/2014/01/17/cleanly-declaring-angularjs-services-with-coffeescript/ . Yes, I know about `$resource`, but I prefer not to use it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
app = angular.module 'BlogExample', [] | |
# Simple controller that loads all blog posts | |
app.controller 'BlogCtrl', ['$scope', 'Blog', ($scope, Blog) -> | |
# Get all the blog posts | |
Blog.all().then (posts) -> | |
$scope.posts = posts | |
# Extend the $scope with our own properties, all in one big block | |
# I like this because it looks like declaring a class. | |
angular.extend $scope, | |
posts: [] | |
# A new, prototype post that will be bound to the "new post" form. | |
newPost: Blog.newPost() | |
# When the "save post" button is clicked: | |
addPost: -> | |
$scope.newPost.save().then -> | |
@posts.push $scope.newPost | |
$scope.newPost = Blog.newPost() | |
] | |
# The Blog service provides access to Posts. We immediately "new" the class | |
# to provide a single instance of the Blog class to the injector. | |
app.factory 'Blog', ['$http', 'Post', ($http, Post) -> | |
new class Blog | |
# Get all blog posts | |
all: -> | |
# Assume a response like: | |
# { "posts": [ { "title": "Hello World", "author": "Ben Hollis", "body": "This is an example." } ] } | |
$http.get('/posts').then (result) -> | |
new Post(post.title, post.author, post.body, true) for post in result.data.posts | |
# Create a new, empty blog post | |
newPost: -> | |
new Post('', '', '') | |
] | |
# This makes the Post class available for injection, rather than an instance of Post. Thus, it doesn't call "new". | |
# | |
# Post represents a single blog post. | |
app.factory 'Post', [ '$http', ($http) -> | |
class Post | |
# Title, Author, and Body are self-explanatory | |
# Persisted tells whether this instance has been saved. | |
constructor: (@title, @author, @body, @persisted = false) -> | |
# Save this post to the server. | |
save: -> | |
$http.post('/posts', title: @title, author: @author, body: @body).then => | |
@persisted = true | |
] |
@hooptie45 that pollute your global namespace, but you can do:
class app.BlogCtrl
constructor: (@scope, @Blog) ->
@Blog.all().then (posts) =>
@scope.posts = posts
angular.extend @scope, @
newPost: => @Blog.newPost()
app.controller 'DemoCtrl', ['$scope', 'Blog', app.BlogCtrl]
How will you Unit test your file blog.js.coffee? With Jasmine for example.
I really like the idea of using Coffee classes in Services, however the way you propose it:
app.factory 'Blog', ['$http', 'Post', ($http, Post) ->
new class Blog
# Get all blog posts
all: ->
# Assume a response like:
# { "posts": [ { "title": "Hello World", "author": "Ben Hollis", "body": "This is an example." } ] }
$http.get('/posts').then (result) ->
new Post(post.title, post.author, post.body, true) for post in result.data.posts
# Create a new, empty blog post
newPost: ->
new Post('', '', '')
]
would be no different than if you simply left out line 27:
app.factory 'Blog', ['$http', 'Post', ($http, Post) ->
# Get all blog posts
all: ->
# Assume a response like:
# { "posts": [ { "title": "Hello World", "author": "Ben Hollis", "body": "This is an example." } ] }
$http.get('/posts').then (result) ->
new Post(post.title, post.author, post.body, true) for post in result.data.posts
# Create a new, empty blog post
newPost: ->
new Post('', '', '')
]
Now if I am able to leave out a line without it affecting the code at all, I can't really see why I would use a class there in the first place. "Just for the sake of using a class" isn't really a good enough reason for me. :/
@bra1n I wrote a whole blog post about my reasoning for this pattern. It's linked from this gist.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This works nice for controllers