GithubHelp home page GithubHelp logo

reagent-project / reagent-cookbook Goto Github PK

View Code? Open in Web Editor NEW
838.0 36.0 87.0 1.02 MB

Examples of how to accomplish specific tasks in a Reagent webapp.

License: MIT License

Clojure 77.90% HTML 17.08% CSS 3.84% JavaScript 1.18%
reagent

reagent-cookbook's Introduction

Reagent Cookbook

Reagent-Project

The goal of this repo is to provide recipes for how to accomplish specific tasks in a reagent webapp.

For updates, follow us on twitter: @ReagentProject. Please include #reagent #cljs when tweeting about reagent.

For video tutorials, subscribe to us on youtube.

Basics

Recipes

Common Starting Point for Recipes

The starting point for reagent-cookbook recipes is reagent-cookbook-template.

$ lein new rc <name of recipe>

Note: reagent-cookbook-template was made specifically for following along with recipes. If you are interested in starting a new reagent application with some batteries included, then reagent-template provides a good starting configuration: $ lein new reagent <name of app>.

Contributing

Recipes are welcomed! Please fork, branch, and submit a pull request.

Also, I would love a PR for:

  • Adding the right externs for advanced compilation of the nvd3 recipe (it's inside old-recipes for now)
  • Adding the right externs for advanced compilation of the mermaid recipe (it's inside old-recipes for now)

LICENSE

Copyright ยฉ 2015 Matthew Jaoudi

Distributed under the The MIT License (MIT).

reagent-cookbook's People

Contributors

adek06 avatar deg avatar efraimmgon avatar gadfly361 avatar inchingforward avatar jacekschae avatar karad avatar karlwestin avatar ku1ik avatar madstap avatar mschaef avatar njordhov avatar nondv avatar piotr-yuxuan avatar sashton avatar smnplk avatar tangarts avatar tankorsmash avatar todokr avatar yatesj9 avatar yogthos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reagent-cookbook's Issues

NVD3 Recipe: undefined is not a function with NVD3 v1.7.1 and D3 v3.5.5

The NVD3 recipe of line chart fails with undefined is not a function at the last line of this snippet-

...
(.addGraph
    js/nv
    (fn []
      (let [chart (.. js/nv -models lineChart
...

To reproduce this issue, just bump the version of NVD3 and D3 as shown below-

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <div id="app"> Loading... </div>
    <!-- nvd3 -->
    <script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js"></script>
    <link href="//cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.1/nv.d3.css" rel="stylesheet">
    <script src="//cdnjs.cloudflare.com/ajax/libs/nvd3/1.7.1/nv.d3.js"></script>

    <script src="/js/app.js"></script>
  </body>
</html>

Now, if you access the demo it will fail with Uncaught TypeError: undefined is not a function. Here are the screenshots that show the error in console and code at the specified line number-

selection_037
selection_038

Call for recipes

Looking for collaborators to add well-documented reagent recipes.

To contribute, please make a folder with a working example. Include a README that has the problem defined as well as a detailed solution. I would prefer clarity over brevity in the solution, especially when displaying code.

Also, let me know if you have any suggestions for future recipes.

reconcile reagent-template and reagent-seed

It's confusing that reagent-project provides both reagent-template and reagent-cookbook, but the latter seems to prefer reagent-seed. Even though there may be plausible use cases for two templates, it's hard as a newcomer to know how to start a new project. For example, I ended up creating multiple projects then eventually manually merging them.

Update dependencies

Since reagent.core/render has been deprecated since 0.10.0 it would be of use beginners to have tutorials using the newest version of reagent.

I'd be able to put in a pull request with the updates.

Routing with secretary and using dispatch!

In the add-routing example we use defroute to change :current-page when navigating. Then view under :current-page is rendered and we've got routing working.
But what if we want to run secretary/dispatch! manually (for example, after form submit to redirect to a different page)?
We will be correctly taken to a the page cause of the state change, but address bar in our browser won't change.

I see a few possible solutions:

  • changing window.location inside defroute call, but that change will call dispatch! again, thus creating an infinite loop
  • using .pushState from History Api inside defroute. That corrects the url, but routing no longer works afterwards...
  • setting window.location in place of dispatch!

Recipes promote use `:render` instead of `:component-function`

I believe it is a mistake to be promoting the use of :render when callingreagent/create-class

For example, I believe this is a mistake:

(defn home-component []
  (reagent/create-class {:render home                    ;;   <--- use of  :render
                         :component-did-mount home-did-mount}))

A renderer function supplied via :render will only ever be called with one parameter (this) which is a pain when you are writing components which need to take multiple parameters (about 99% of them). Newbies are constantly surprised about not getting their parameters passed into render. I've found myself answering the question steadily over the last year.

The alternative is to use :component-function instead of :render. My write up

Dan's Blessing

Thanks so much for this project!

Sorry, this is not an issue and I can close at end of day, but I just wanted to give y'all a shout out for the great work.

I had fumbled through a few outdated tutorials about handling navigation for reagent, then I stumbled on this:
https://github.com/reagent-project/reagent-cookbook/blob/master/recipes/add-routing/src/cljs/add_routing/core.cljs#L1

Perfect little tutorials in here! Short, simple, clear, very usable. Can't tell you how much I appreciate this type of help when learning a bunch of new things at once; coming back to clojure, new to cljs, service worker, indexed db, structuring things as a single-page app... all super new and interesting and resources like this are invaluable.

THANK YOU!!!

Sortable

The problem with the sortable example(s) is it doesn't explain how to get the sorting data out of it...

I'd like to feed the positional data back into my reagent app so I can send it to a backend API, for example.

file upload example is advertising, not tutorial

I'd like to see an example of how to open a file and view its contents in cljs. The current recipe is effectively an advertisement for a convoluted paid service, not an example of how to do this relatively simple action.

File upload example: callback function?

Thanks for putting these recipes together, that's very useful.

While testing the file upload example, I could not figure what callback function to use. My goal is to retrieve the URL of a freshsly uploaded document.

Thanks for any hint!

File upload recipe

It would be great to have a recipe for (possibly multiple) file upload ๐Ÿ˜„

More minimal templates?

Wow, I love the idea and the examples so far! They are super useful, thank you! Would it be an idea to have more minimal boilerplates around the examples? I get lost every time I dive into a new example and need to click some files/folders to find what I'm searching for. For example routing is only relevant for the routing example, still it's included in every example. Would prefer to see a single cljs file in the root of every example folder showing only the bare minimum solution. Also it would be nice to have some demos ready hosted/included somewhere. I'd be happy to contribute if you need help.

`test-example-with-ReactTestUtils` fails with error

Trying to get testing with reagent working using react-test-utils, but not having any luck. The example recipe fails like so:

Caused by: clojure.lang.ExceptionInfo: No such namespace: react, could not locate react.cljs, react.cljc, or JavaScript source providing "react" in file out/reagent/impl/component.cljs {:tag :cljs/analysis-error}

Tip: Improving devcards experience with error-boundary

I wanted to share a few tricks that have been very useful to me, but not sure where to do it, so figured I'd post them here.

First: I'm a big user and proponent of devcards, but one challenge I often run into is that when I get an unhandled error in a card, the whole page shuts down and i have to guess at what caused there error.

the lovely error-boundary component from recalcitrant solves this problem nicely -- https://github.com/pesterhazy/recalcitrant

In order to use that error boundary in devcards, you have to go through a bit of ceremony

(defn ops []
(assert false)
[:div "hey"])

(defcard oops
(r/as-element [(fn [] [error-boundary [ops]])]))

not, if you just tried to do (defcard-rg oops [ops]), the error would stop devcards from reloading, and if you refreshed your page you would just get thrown back to your index of all cards

having a little helper function

(defn with-boundary [elem]
  (reagent/as-element [(fn [] [recalcitrant.core/error-boundary
                         elem])]))

makes it real easy to have devcards that print errors to the console rather than shutting down on you

(defcard safe
(with-boundary [ops])

and you'll load just fine, plus once you fix what causes the error it'll reload right away

Selectize recipe

Hello,

I really appreciate you putting together this cookbook for Reagent and I would like to contribute a recipe for getting Selectize working with Reagent. It's pretty rough and could probably be cleaned up a bit, but it gets the job done.

For a multiselect control which updates due to changing options:

;; groups-data contains the groups which can be selectable in the Selectize
;; control. groups-data may also be updated elsewhere in the app
(def groups-data (atom [{:id 1 :label "something" :count 5}]))

;; atom for keeping track of selected groups
(def selected-groups (atom []))

;; groups-data gets updated somewhere else...

(defn group-selectize-component 
  "Create div container for Selectize control"
  []
  ;; deref atoms that the group select depends on like `groups-data`
  (deref groups-data)
  [:div {:id "groups-container"}
   ;; Since Selectize manipulates the DOM and changes the position of select 
   ;; input, we can't set it up like this:
   ;; [:label {:for "mst-groups"} "Select groups:"]
   ;; [:select {:id "mst-groups"
   ;;          :name "mst-groups"
   ;;          :multiple true
   ;;          :style {:width "100%"}}]
   ;; If we want to update the Selectize options we have to reinitialize the
   ;; innerHTML in this div container  
             ])

(defn group-selectize! 
  "Mount/update the Selectize component"
  []
  ;; Need to set the innerHTML of the Selectize container to contain a select
  ;; and label. It's hacky because of the DOM manipulations that Selectize 
  ;; performs
  (set! (.-innerHTML (by-id "groups-container"))
        "<label for=\"groups\">Select groups</label>
        <select id=\"groups\" name=\"groups\" multiple style=\"width:100%\"></select>")
  (let [el (js/jQuery "select#groups")
        opts (vec (map (fn [{:keys [id label count]} 
                                     {:id id
                                      :label label
                                      ;; in order to force a descending order
                                      ;; of options, multiplication of the 
                                      ;; count by a negative number is
                                      ;; necessary
                                      :count (+ count (* count -100))})
                  @groups-data))
        ;; setup the settings for the Selectize control
        settings {:options opts
                  :valueField "id"
                  :labelField "label"
                  :searchField "id"
                  :sortField "count"
                  :create false
                  :maxOptions nil
                  :hideSelected true
                  :plugins ["remove_button"]
                  :onChange (fn [e] 
                                (let [selected-ids (map keyword (js->clj e))
                                      matching-groups (filter (fn [x] 
                                       (some #(= (get x :id) %) selected-ids) @groups-data))]
                                (reset! selected-groups matching-groups)))}
        ;; maybe have the top 5 largest groups selected by default
        default-groups (->> @groups-data 
                            (sort-by :count)
                            (take 5)
                            (map :id))
        ;; setup the Selectize control with `settings` on HTML element `el`
        select-jquery (.selectize el (clj->js settings))
        ;; get the Selectize control object so that the 
        selectize-select (.-selectize (aget select-jquery 0))]
    (reset! selected-groups default-groups)
    ;; set default selection
    (.setValue selectize-select (clj->js default-groups))))

(defn group-select 
  "Use reagent/create-class to specify how the component should be initially 
  rendered and what should happen when it needs to mount/update."
  []
  (reagent/create-class
   {:render group-select-component
    ;; using the same function for mounting and updating of the component
    :component-did-mount group-selectize!
    :component-did-update group-selectize!}))

;; Use the Selectize component somewhere in the app
(defn some-app-page []
  [:div
    [group-select]])

Update ReactCSSTransitionGroup example?

The ReactCSSTransitionGroup example says it's for when "You want to use ReactCSSTransitionGroup in your reagent web application".

The React animation docs say the "add-on" version is deprecated, though:

ReactTransitionGroup and ReactCSSTransitionGroup have been moved to the react-transition-group package that is maintained by the community. Its 1.x branch is completely API-compatible with the existing addons.

Fortunately, the latest version (2.4.0) of react-transition-group is in cljsjs, so it looks like it should be straightforward to update.

Instead of:

[reagent "0.5.1" :exclusions [cljsjs/react]]
[cljsjs/react-with-addons "0.13.3-0"]

it'd be:

[reagent "0.5.1"]
[cljsjs/react-transition-group "2.4.0-0"]

and the adapt-react-class call would need to be something like:

(def css-transition-group
  (reagent/adapt-react-class react-transition-group/CSSTransition))

Also, .foo-leave would need to be updated to .foo-exit.

I'm still missing something, though, because the compiled JS is giving me a ReferenceError. Help welcome!

Please correct reagent-modal to reagent-bootstrap-modal

This is not showing how to create a modal in reagent, but rather how to embed the modal bootstrap component.
That's not what I was looking for, under that title ;)
It's interesting, but I'm not using bootstrap nor jquery.

Cheers, Mathias

PDF.JS

Pdf.js is a very cool toolkit for working with pdfs online, it is packaged up in cljsjs, but unfortunately requires the use of web workers, so isn't as simple as just requiring cljsjs and going after it. To someone not too familiar with js/cljs interop this is pretty difficult, would be amazing if someone could build a recipe for this

https://github.com/mozilla/pdf.js/

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.