reagent-project / reagent-cookbook Goto Github PK
View Code? Open in Web Editor NEWExamples of how to accomplish specific tasks in a Reagent webapp.
License: MIT License
Examples of how to accomplish specific tasks in a Reagent webapp.
License: MIT License
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.
The reagent-server-rendering is different from react server-rendering.
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!!!
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]])
Line 80 in the Draggable recipe's README should be .draggable
not .Datatable
.
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
I was unable to get the google map to render until I corrected the home function:
[:div [(r/create-class ...)]]ย
as shown in the third comment of this Stack Overflow answer:
https://stackoverflow.com/questions/38632718/adding-google-maps-to-luminus-reagent-page by Walton Hoops.
Let me know if you would consider a pull request. Thank you for all your great work on this project.
Best,
Evan
The google-maps cljsjs package can be required instead of declaring custom externs in the Google Maps example. Same for highcharts externs.
Are you interested in drag and drop recipe?
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.
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
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
In the filter-table example, index.html references app.js, but the corresponding project.clj mentions filter_table.js. The example works better when these match.
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.
It would be great to have a recipe for (possibly multiple) file upload ๐
Can you please license these cookbooks? Thanks!
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}
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.
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-
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:
window.location
inside defroute
call, but that change will call dispatch!
again, thus creating an infinite loop.pushState
from History Api inside defroute
. That corrects the url, but routing no longer works afterwards...window.location
in place of dispatch!
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!
How do we find examples of separating our codebase up into modules / pages for example, and then requiring them?
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!
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.
(defn markdown-component [content]
(fn []
[:div {:dangerouslySetInnerHTML
{:__html (-> content str js/marked)}}]))
needs to be:
(defn markdown-component [content]
(fn [content]
[:div {:dangerouslySetInnerHTML
{:__html (-> content str js/marked)}}]))
otherwise only the initial value will be rendered.
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.
Use advanced compilation and add externs
As a user, I've found the documentation around reagent-cursor project slightly thin. A real world useage would really help.
Thanks!
Most of these examples use jquery. Why not use google closure?
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
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.