Tuesday, July 3, 2012

Working together: AngularJS and Coffeescript

While building my first AngularJS application, I followed the official tutorial, and also other useful examples I found on the web. The examples were all in javascript of course, which was fine in the beginning, but after a while I started to miss the elegance of Coffeescript's syntax.

Changing an AngularJS app from javascript is not as straight forward as changing the syntax. The reason for this is the Coffeescript compiler's reverence for the global scope. All coffee script code is wrapped in a function to protect the global scope from pollution and conflict.

Take the following javascript controller definition from the official tutorial as an example. If you simply convert this to Coffeescript you will get a PhoneListCtrl not found exception in your browser console.


function PhoneListCtrl($scope) {
  $scope.phones = [
    {"name": "Nexus S",
     "snippet": "Fast just got faster with Nexus S."},
    {"name": "Motorola XOOM™ with Wi-Fi",
     "snippet": "The Next, Next Generation tablet."},
    {"name": "MOTOROLA XOOM™",
     "snippet": "The Next, Next Generation tablet."}
  ];
}

PhoneListCtrl = ($scope) ->
  $scope.phones = [
    {"name": "Nexus S",
     "snippet": "Fast just got faster with Nexus S."},
    {"name": "Motorola XOOM™ with Wi-Fi",
     "snippet": "The Next, Next Generation tablet."},
    {"name": "MOTOROLA XOOM™",
     "snippet": "The Next, Next Generation tablet."}
  ]

The quickest solution is to deliberately attach the controller to the window scope, thus counteracting the protection to the global scope given by Coffeescript compiler. It is as simple as that!


window.PhoneListCtrl = ($scope) ->
  $scope.phones = [
    {"name": "Nexus S",
     "snippet": "Fast just got faster with Nexus S."},
    {"name": "Motorola XOOM™ with Wi-Fi",
     "snippet": "The Next, Next Generation tablet."},
    {"name": "MOTOROLA XOOM™",
     "snippet": "The Next, Next Generation tablet."}
  ]

BUT, for those who like to follow best practices, and avoid the sneering of other developers the above solution might not be enough. If this is the case, you can make use of the global angular object to register a controller for a given module.


angular.module('phoneApp').controller 'PhoneListCtrl', ($scope) ->
  $scope.phones = [
    {"name": "Nexus S",
     "snippet": "Fast just got faster with Nexus S."},
    {"name": "Motorola XOOM™ with Wi-Fi",
     "snippet": "The Next, Next Generation tablet."},
    {"name": "MOTOROLA XOOM™",
     "snippet": "The Next, Next Generation tablet."}
  ]

This registers the controller alright, but you might find you are still seeing the controller not found error. The reason for this is that the code using your controller expected it to be operating at the global scope as it is in the Angular tutorial.


angular.module('phonecat', []).
  config(['$routeProvider', function($routeProvider) {
  $routeProvider.
      when('/phones', {templateUrl: 'partials/phone-list.html',   controller: PhoneListCtrl}).
      when('/phones/:phoneId', {templateUrl: 'partials/phone-detail.html', controller: PhoneDetailCtrl}).
      otherwise({redirectTo: '/phones'});
}]);

Fortunately AngularJS comes to our rescue in the most elegant of ways. We simply have to change the reference to the controller to be a string , and we have lift off!


angular.module('phonecat', []).
  config(['$routeProvider', function($routeProvider) {
  $routeProvider.
      when('/phones', {templateUrl: 'partials/phone-list.html',   controller: 'PhoneListCtrl'}).
      when('/phones/:phoneId', {templateUrl: 'partials/phone-detail.html', controller: PhoneDetailCtrl}).
      otherwise({redirectTo: '/phones'});
}]);

10 comments:

  1. Nice job. I've just worked through the first part of your post.
    The definition of $scope.phones loses some of the elegance of coffee with all the braces and brackets and commas, and so on.

    What do you think about this as an alternative:
    http://rsilt.blogspot.com/2012/09/coffeescript-and-angular.html

    ReplyDelete
  2. what do your unit tests for the controllers look like when you attach it to the window scope ?

    ReplyDelete
  3. đồng tâm
    game mu
    cho thuê nhà trọ
    cho thuê phòng trọ
    nhac san cuc manh
    số điện thoại tư vấn pháp luật miễn phí
    văn phòng luật
    tổng đài tư vấn pháp luật
    dịch vụ thành lập công ty trọn gói
    lý thuyết trò chơi
    đức phật và nàng
    hồ sơ mật dinh độc lập
    đừng hoang tưởng về biển lớn
    chiến thắng trò chơi cuộc sống
    lượng tử
    ngồi khóc trên cây
    truy tìm ký ức
    mặt dày tâm đen
    thế giới như tôi thấy

    Vương Đức Vọng thấy Lưu Phong, nói nghiêm túc, không giống như đang nói đùa, nên trong lòng cảm thấy sảng khoái, cười dài nói: “Tốt, ta ở Lương Châu chờ tin tốt của ngươi.”
    Ngừng một chút, Vương Đức Vọng ý vị thâm sâu liếc mắt nhìn hắn, thở dài nói: “Phong nhi, ngươi hôm nay hãy thật lòng cho ta biết, trong lòng ngươi có Đông Đông không? Nếu thật sự trong lòng ngươi nghĩ tới nó thì hôm nay ta liền làm chủ, hứa gả nó cho ngươi.”
    Lưu Phong quay đầu lại liếc nhìn Vương Đông Đông một cái, thấy nàng khẽ cắn môi, mắt rưng rưng nước mắt, thoáng do dự một chút rồi thở dài: “Vương đại nhân, ta đã từng nói câu này, chuyện tình cảm phải có thời gian. Bất quá người yên tâm, ta sẽ chiếu cố tốt đến nàng.”
    Vương Đức Vọng thở dài một hơi, câu trả lời của Lưu Phong làm hắn hơi thất vọng, nhưng Lưu Phong cũng không nói là không thích.
    “Cũng được, chuyện của bọn trẻ các ngươi, các ngươi tự xử lý đi, ta cũng không quản.” Vương Đức Vọng đột nhiên hỏi: “Phong nhi ngươi có ý định gì chưa? Ví dụ như nhảy vào trong chốn quan trường?”
    Lưu Phong thấp giọng nói: “Vương Đại nhân nói thế là có ý gì?”
    “Phong nhi, mấy ngày trước ta có nghe Hoàng thượng có ý muốn triệu ngươi về kinh, hiện tại triều đình đang thương nghị, cũng không biết có kết quả gì chưa.” Vương Đức Vọng làm quan đã hơn 10 năm, cũng có chút mối quan hệ, tin tức từ kinh đô hắn đều biết trước tiên.
    “ Ồ, có việc này sao?” Lưu Phong lạnh nhạt nói: “Ta còn chưa có quyết định gì, cứ đợi xem ý tứ của triều đình và bệ hạ đã.” Nói thật, Lưu Phong cũng đã có ý muốn tiến kinh để phát triển, dù sao chỉ có đến kinh đô mới có thể nắm chắc tình thế, phát triển lực lượng của mình.

    ReplyDelete
  4. Angular JS is a structural framework for dynamic web application and angular's data binding eliminates much of the code that you would otherwise write it.
    Angularjs Training in Chennai | Angularjs training Chennai

    ReplyDelete
  5. Given so much info in it, These type of articles keeps the users interest in the website, and keep on sharing more ..Best Angularjs Training in Chennai|Angularjs Training in Chennai

    ReplyDelete