Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Angular Tutorial Rewritten to ClojureScript

DZone's Guide to

Angular Tutorial Rewritten to ClojureScript

· Web Dev Zone
Free Resource

Learn how to build modern digital experience apps with Crafter CMS. Download this eBook now. Brought to you in partnership with Crafter Software

Over the last few months I learned some more ClojureScript and I finally came back to Angular. First I followed their excellent tutorial. Then I decided to rewrite it to plain Clojure and ClojureScript, and it went pretty well.

I made one change on the go – rather than load JSON files directly from disk, it talks to a Ring-provided service.

Raw files are below:
(ns tutorial.app
  (:require [tutorial.controllers :as ctrl]))

(defn ng-route [provider path route-spec]
  (.when provider path (clj->js route-spec)))

(defn ng-route-otherwise [provider route-spec]
  (.otherwise provider (clj->js route-spec)))

(doto (angular/module "phonecat" (array "phonecatFilters" "phonecatServices"))
  (.config (array "$routeProvider"
                  (fn [$routeProvider]
                    (doto $routeProvider
                      (ng-route "/phones" {:templateUrl "partials/phone-list.html"
                                           :controller ctrl/phone-list-ctrl})
                      (ng-route "/phones/:phoneId" {:templateUrl "partials/phone-detail.html"
                                                    :controller ctrl/phone-detail-ctrl})
                      (ng-route-otherwise {:redirectTo "/phones"}))))))

(ns tutorial.controllers)

(defn ^:export phone-list-ctrl [$scope Phone]
  ; Unfortunately, with custom actions (like Phone.query) the advanced
  ; compilation will lose the name, so we have to get it by string explicitly
  (aset $scope "phones" ((aget Phone "query")))
  (aset $scope "orderProp" "age"))

(aset phone-list-ctrl "$inject" (array "$scope" "Phone"))

(defn ^:export phone-detail-ctrl [$scope $routeParams Phone]
  ; Setting $scope.phone from "right hand side" and $scope.mainImageUrl
  ; from success callback is nuts, but that's what the tutorial does
  (aset $scope "phone" (.get Phone
                         (clj->js {:phoneId (aget $routeParams "phoneId")})
                         (fn [phone] (aset $scope "mainImageUrl" (first (.-images phone))))))
  (aset $scope "setImage" (partial aset $scope "mainImageUrl")))

(aset phone-detail-ctrl "$inject" (array "$scope" "$routeParams" "Phone"))

(ns tutorial.filters)

(doto (angular/module "phonecatFilters" (array))
  (.filter "checkmark"
    (fn []
      (fn [input]
        (if input "\u2713" "\u2718")))))

(ns tutorial.services)

(doto (angular/module "phonecatServices" (array "ngResource"))
  (.factory "Phone"
    (array "$resource"
           (fn [$resource]
             ($resource
               "app/phones/:phoneId"
               (clj->js {})
               (clj->js {:query {:method "GET" :params {:phoneId ""} :isArray true}}))))))

All code is available at GitHub.

It’s almost a one-to-one rewrite from JavaScript. Compared to the original, it is pretty ugly – for two reasons. The first is that I wanted it to work with advanced Closure compiler, so I had to use explicit dependencies. The second is that there is a lot JavaScript interop.

Many of those issues can be mitigated with a glue layer. It is possible to write functions or macros that would automatically generate array syntax for functions with injected dependencies, create functions automatically converting arguments with clj->js, and provide a better replacement for $scope.property = function(...){...}.

I may do that later, but firstly I wanted to have a one-to-one replacement.






Crafter is a modern CMS platform for building modern websites and content-rich digital experiences. Download this eBook now. Brought to you in partnership with Crafter Software.

Topics:

Published at DZone with permission of Konrad Garus, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}