AngularJS и CoffeeScript это отличная комбинация, не смотря на то, что CoffeeScript не пользуется большой популярностью в комьюнити AngularJS. В статье будут представлены несколько приемов, которые «облегчат» ваш код на AngularJS.
Короткая запись определения функции
В Angular используется большое число анонимных функций, и как следствие, используя короткую запись определения функции, можно сэкономить уйму времени. Как пример, давайте создадим директиву ‘enter key’, которая вычислияет выражение по нажатии на клавишу Enter с задержкой. Конечно, эта директива не несет в себе практической значимости, но должна дать представление о том, как взаимодействуют AngularJS и CoffeeScript.
Итак, как используем:
<input enter-key="submit()" enter-key-delay="10" />
JavaScript код:
app.directive('enterKey', function ($timeout) { return function (scope, elem, attrs) { elem.bind('keydown', function (e) { if (e.keyCode === 13) { $timeout(function () { scope.$apply(attrs.enterKey); }, +attrs.enterKeyDelay); } }); } });
сравните его с CoffeeScript:
app.directive 'enterKey', ($timeout) -> (scope, elem, attrs) -> elem.bind 'keydown', (e) -> if e.keyCode is 13 $timeout -> scope.$apply attrs.enterKey , +attrs.enterKeyDelay
В CoffeeScript символ -> используется для определения функции с параметрами, заключенными в круглые скобки перед ней. Если же функция не имеет параметров, то скобки не нужны, примером служит функция переданная в $timeout.
Мы избежали использования ключевого слова function 4 раза в 10 строчках кода, при этом код стал более читаемым и сократилось время для его написания. Также нет необходимости использования оператора return, т.к. CoffeeScript(как и Ruby) автоматически возвращает значение последнего выражения в функции.
Automatic Returns
Автоматический (или неявный) возврат — это еще одно преимущество, которое делает написание Angular кода быстрее и проще. Ниже представлены несколько примеров где видно полезность автоматического возврата. Разница, конечно, не большая, но в большом проекте будет заметна.
Фильтры
app.filter('capitalise', function (str) { return str.charAt(0).toUpperCase() + str.slice(1); });
app.filter 'capitalise', (str) -> str.charAt(0) + str[1..]
Бонусом в этом примере является синтаксис получение части массива str.slice(1) vs. str[1..].
Фабрики
app.factory('urlify', function (text) { // nb: не используйте это в реальных приложениях return text.toLowerCase().replace(" ", ""); });
app.factory 'urlify', (text) -> text.toLowerCase().replace " ", ""
Директивы (опять)
В этом случае мы используем директиву определения объекта. Использование автоматического возврата CoffeeScript, синтаксиса объектного стиля YAML и короткую запись определения функции делает код намного более читаемым. Следующий пример взят с документации AngularJS.
app.directive('directiveName', function factory(injectables) { return { priority: 0, template: '<div></div>', templateUrl: 'directive.html', replace: false, transclude: false, restrict: 'A', scope: false, controller: function ($scope, $element, $attrs, $transclude, otherInjectables) { ... }, compile: function compile(tElement, tAttrs, transclude) { return { pre: function preLink(scope, iElement, iAttrs, controller) { ... }, post: function postLink(scope, iElement, iAttrs, controller) { ... } } }, link: function postLink(scope, iElement, iAttrs) { ... } } });
app.directive 'directiveName', (injectables) -> priority: 0 template: '<div></div>' templateUrl: 'directive.html' replace: false transclude: false restrict: 'A' scope: false controller: ($scope, $element, $attrs, $transclude, otherInjectables) -> ... compile: (tElement, tAttrs, transclude) -> pre: (scope, iElement, iAttrs, controller) -> ... post: (scope, iElement, iAttrs, controller) -> ... link: (scope, iElement, iAttrs) -> ...
Автоматический возврат и объектный синтаксис используются как для директивы определения объекта, так и внутри функции compile.
Классы
В CoffeeScript классы являются наиболее приятными включениями в возможности языка. Вот как они выглядят:
class Animal constructor: (@name) -> move: (meters) -> alert @name + " moved #{meters}m." snake = new Animal('snake') snake.move(10) # alerts "snake moved 10m."
В CoffeeScript символ @ является короткой записью для this. Поэтому @name
станет this.name. Кроме того, добавление символа @ к параметру функции автоматически добавляет его к this, как видно в конструкторе Animal.
Вот пример аналогичного кода на JavaScript. Он, конечно, не идентичен скомпилированному коду CoffeeScript, но функционально эквивалентен.
function Animal(name) { this.name = name; } Animal.prototype.move = function (meters) { alert(this.name + "moved" + meters + "m.") } var snake = new Animal('snake') snake.move(10) // alerts "snake moved 10m.", as before
CoffeeScript создает именованную функцию и добавляет методы к ее prototype. В Angular это полезно в двух случаях: в сервисах и с синтаксисом new Controller.
Сервисы
В то время как функция фабрика будет непосредственно добавлена в другую функцию, в случае сервиса вначале будет создан его экземпляр перед добавлением. Более подробное объяснение различий можно найти в этой статье.
Из статьи, упомянутой выше, взят пример сервиса:
var gandalf = angular.module('gandalf', []); function Gandalf() { this.color = 'grey'; } Gandalf.prototype.comeBack = function () { this.color = 'white'; } gandalf.service('gandalfService', Gandalf); var injector = angular.injector(['gandalf', 'ng']); injector.invoke(function (gandalfService) { console.log(gandalfService.color); gandalfService.comeBack() console.log(gandalfService.color); });
Выглядит как JavaScript код, скомпилированный из класса CoffeeScript. Поэтому, вместо редактирования prototype функции напрямую, мы можем использовать класс CoffeeScript:
gandalf = angular.module 'gandalf', [] gandalf.service 'gandalfService', class Gandalf constructor: -> @color = 'grey' comeBack: -> @color = 'white' injector = angular.injector ['gandalf', 'ng'] injector.invoke (gandalfService) -> console.log gandalfService.color gandalfService.comeBack() console.log gandalfService.color
Здесь мы передаем класс в сервис функцию. Вы можете определить его до сервиса и уже затем передать в сервис, но я предпочитаю чтобы класс был доступен исключительно через сервис.
Для того чтобы показать внедрение зависимостей, давайте создадим gandalf, который «возвращается» с задержкой, используя $timeout сервис.
gandalf.service 'gandalfService', class Gandalf constructor: (@$timeout) -> @color = 'grey' comeBack: (time) -> # 'двойная стрелка' в coffeescript связывает функцию с уже существующим # значением 'this', поэтому @color - это та же сама переменная, что и выше. @$timeout => @color = 'white' , time
Имя переменной в аргументах будет $timeout, поэтому внедрение зависимостей Angular будет продолжать работать. Добавление зависимостей к объекту позволяет нам иметь доступ к ним в методах, например, в comeBack.
Контроллеры
В AngularJS 1.1.5 представлен новый синтаксис контроллеров. Вы можете посмотреть видео для подробностей, но по сути новый синтаксис позволяет классу быть переданным как контроллер, а не функция с областью видимости. Поэтому html-код примера todoList на странице AngularJS будет выглядеть следующим образом:
<body ng-app="todoApp"> <div ng-controller="TodoCtrl as todos"> <span>{{todos.remaining()}} of {{todos.list.length}} remaining</span> [<a href="" ng-click="todos.archive()">archive</a>] <ul> <li ng-repeat="todo in todos.list"> <input type="checkbox" ng-model="todo.done"> <span class="done-{{todo.done}}">{{todo.text}}</span> </li> </ul> <form ng-submit="todos.addTodo()"> <input type="text" ng-model="todos.input" placeholder="add a new todo"> <input type="submit" value="add"> </form> </div> </body>
и использовать этот CoffeeScript класс в качестве контроллера:
app = angular.module 'todoApp', [] app.controller 'TodoCtrl', class TodoCtrl list: [ text: "learn coffescript" done: false , text: "learn angular" done: true ] addTodo: -> @list.push text: @input done: false @input = '' remaining: -> count = 0 for todo in @list count += if todo.done then 0 else 1 count archive: -> oldList = @list @list = [] for todo in oldList unless todo.done @list.push todo
Заключение
Как вы могли убедиться, CoffeeScript отличный компаньон для AngularJS. Хотя не для всех удобство записи CoffeeScript перевешивает его недостатки.
Есть целый ряд и других полезных функций, о которых я не упомянул в этой статье, таких как: параметры по умолчанию, экзистенциальный оператор, массивы и объекты. Все это вместе делает CoffeeScript приятным и продуктивным языком для написания программ. Если вы еще не рассматривали возможность его использования, перейдите на официальный сайт за подробностями.
ссылка на оригинал статьи http://habrahabr.ru/post/188406/
Добавить комментарий