I am doing an Ajax GET from my Reagent application, to load some stuff from the database.
I am not entirely sure what is the best way of getting the result of such ajax call to my page, considering that if I put it in an atom, then Reagent automatically re-renders a component when an atom is dereferenced, which means I get an infinite sequence of ajax calls.
For some code,
(def matches (atom nil))
(defn render-matches [ms]
(reset! matches (into [:ul] (map (fn [m] ^{:key m}[:li m])
(walk/keywordize-keys (t/read (t/reader :json) ms)))))
This function basically creates a [:ul [:li "Stuff here"] [:li "And here"]]
Which i would like displayed on my page, which now has the following code.
(defn standings-page []
(GET "/list-matches"
{:handler render-matches})
#matches)
I think it's better to save only data in an atom and to generate the HTML as part of the component logic.
Also it's better to trigger the AJAX call outside the render phase, for example, before the component will mount, or as the result of an event (on-click on a button for example).
Like this:
(def matches (atom nil))
(defn component []
(let [get-stuff (fn [] (GET "/..." :handler (fn [response]
(reset! matches (:body response))))]
(get-stuff) <-- called before component mount
(fn []
[:ul
(for [m match]
^{:key ...}
[:li ...])])))
This is called form-2 in this post.
Related
I want to implement caching of api in clojure, In my application I have api's which are called for some of the functionalities. I want to reduce that api calls. I want to use clojure.core.cache.wrapped which is implemented upon clojure.core.cache. I want to cache my api call response base on the url.
The url is GET and has query inside the url that differentiates the response
for eg
http://localhost:3000/:clientid/get_data
Sample code
(:require [clojure-mauth-client.request :refer [get!]]
[clojure.core.cache.wrapped :as cw])
(def my-cache (cw/ttl-cache-factory {} :ttl 60000))
(defn get-data-caller [cid]
(cw/lookup-or-miss my-cache cid get-data))
(defn get-data [cid]
(let [req-url (str "/api/get-data?id=" cid)
response (retry-request (sign-credentials #(get! base-url req-url)) 3)]
(println response))))
I want to implement in a way that it caches depending on the cid.
In above code 3 is max-retries
With current implementation I am getting below error.
In my current code it is calling the api again and again
I got the solution, The main mistake I made here is that I implemented this in
get-data-caller
lookup-or-miss actually accepts 3 params
lookup-or-miss [cache key fn]
Here
1. cache is the one that we create.
2. key that we want to use as 'key' in our caching
3. The third has to be the function, that takes 'key' as an arg and gets data for us.
So lookup-or-miss will first check if the we have cached data for the 'key' passed, if not then, that will be passed as an arg to the third arg (i.e the fn) and get the fresh data.
If the cache data is not present for the key, then the fn in the third arg will be called with key as arg to get the data.
With above understanding I did rewrite my code as below
(:require [clojure-mauth-client.request :refer [get!]]
[clojure.core.cache.wrapped :as cw])
(def my-cache (cw/ttl-cache-factory {} :ttl 60000))
(defn http
[url]
(retry-request (sign-credentials #(get! url)) 3))
(defn get-data-caller [cid]
(get-data cid))
(defn get-data [cid]
(let [req-url (str "/api/get-data?id=" cid)
response (cw/lookup-or-miss my-cache req-url http-request)]
(println response))))
So here lookup-or-miss will search req-url key in my-cache, if present it will directly return the value stored, if not then it will call http-request with req-url as an arg
So lookup-or-miss will be executed something like this;
pseudo code for understanding
(if (contains? my-cache req-url)
(:req-url my-cache)
(http-request req-url))
I have a function which basically inserts function () {}; but properly indented and the cursor positioned appropriately:
(defun insert-function-js ()
(insert "function () {
};"))
(define-key evil-normal-state-map (kbd "SPC dg")
(lambda ()
(interactive)
(call-interactively 'evil-insert)
(insert-function-js)
(evil-force-normal-state)
(call-interactively 'evil-visual-char)
(call-interactively 'evil-previous-line)
(call-interactively 'indent-region)
(call-interactively 'evil-open-below)))
This seems very cumbersome. I would guess there is a better way to write this functionality! One that better leverages elisp's capabilities.
Thanks for the help!
As an answer to your first question, you could use yasnippet and a snippet based on the function-snippet provided with Spacemacs [1] to do this for you:
# -*- mode: snippet; require-final-newline: nil -*-
# name: my-function
# key: fn
# --
function () {
$0
};
If you put this snippet in a new file in ~/.emacs.d/private/snippets/, you can expand it by typing fn and then pressing M-/ [2]. If yas-indent-line is set to 'auto (which it is by default in Spacemacs), then the function should be indented correctly, and the $0 in the snippet puts your cursor in that position after insertion.
The yasnippet-expansion forms a single undo-action.
[1] The default function-snippet can be found in ~/.emacs.d/elpa/yasnippet-<VERSION>/snippets/js-mode
[2] using the default Spacemacs bindings, this calls hippie-expand, which in turn calls yas-expand.
My goal is to create a menu item (a span) which, when clicked, does
three things. First, it sets some state on the server (addTurn), then
it creates a new element (renderEmptyTurnOn) on the server and sends
it to the client. Then the client, having received the new element,
appends it to a specific element with class #zdTurns. I only want one
server roundtrip.
The code below fails because renderEmptyTurnOn is expecting a canvas,
but I am passing it a script instead.
Is there an idiomatic way to do this using vanilla seaside and
jquery?
renderMenuOn: h
h div
class: 'zdDialogMenu';
with: [
h span
onClick:
(h jQuery ajax
callback: [ self dialog addTurn ];
script: [ :s | s << ((s jQuery class: #zdTurns) append: (s jQuery html: (self renderEmptyTurnOn: s))) ]);
with: 'Add Turn' ]
You almost nailed it. The argument of an append: message on a jQuery instance accepts a renderable object. This could be a string, a Seaside component or a block. That means you can do it as follows:
renderMenuOn: h
h div
class: 'zdDialogMenu';
with: [
h span
onClick: (h jQuery ajax
script: [ :s |
self dialog addTurn.
s << ((s jQuery class: 'zdTurns') append: [:r | self renderEmptyTurnOn: r ]) ]);
with: 'Add Turn' ]
I need to update multiple targets when a link is clicked.
This example builds a list of links.
When the link is clicked, the callback needs to populate two different parts of the .html file.
The actual application uses bokeh for plotting.
The user will click on a link, the 'linkDetails1' and 'linkDetails2' will hold the script and div return from calls to bokeh.component()
The user will click on a link, and the script, div returned from bokeh's component() function will populate the 'linkDetails'.
Obviously this naive approach does not work.
How can I make a list of links that when clicked on will populate two separate places in the .html file?
################################
#views/default/test.html:
{{extend 'layout.html'}}
{{=linkDetails1}}
{{=linkDetails2}}
{{=links}}
################################
# controllers/default.py:
def test():
"""
example action using the internationalization operator T and flash
rendered by views/default/index.html or views/generic.html
if you need a simple wiki simply replace the two lines below with:
return auth.wiki()
"""
d = dict()
links = []
for ii in range(5):
link = A("click on link %d"%ii, callback=URL('linkHandler/%d'%ii), )
links.append(["Item %d"%ii, link])
table = TABLE()
table.append([TR(*rows) for rows in links])
d["links"] = table
d["linkDetails1"] = "linkDetails1"
d["linkDetails2"] = "linkDetails2"
return d
def linkHandler():
import os
d = dict()
# request.url will be linked/N
ii = int(os.path.split(request.url)[1])
# want to put some information into linkDetails, some into linkDiv
# this does not work:
d = dict()
d["linkDetails1"] = "linkHandler %d"%ii
d["linkDetails2"] = "linkHandler %d"%ii
return d
I must admit that I'm not 100% clear on what you're trying to do here, but if you need to update e.g. 2 div elements in your page in response to a single click, there are a couple of ways to accomplish that.
The easiest, and arguably most web2py-ish way is to contain your targets in an outer div that's a target for the update.
Another alternative, which is very powerful is to use something like Taconite [1], which you can use to update multiple parts of the DOM in a single response.
[1] http://www.malsup.com/jquery/taconite/
In this case, it doesn't look like you need the Ajax call to return content to two separate parts of the DOM. Instead, both elements returned (the script and the div elements) can simply be placed inside a single parent div.
# views/default/test.html:
{{extend 'layout.html'}}
<div id="link_details">
{{=linkDetails1}}
{{=linkDetails2}}
</div>
{{=links}}
# controllers/default.py
def test():
...
for ii in range(5):
link = A("click on link %d" % ii,
callback=URL('default', 'linkHandler', args=ii),
target="link_details")
...
If you provide a "target" argument to A(), the result of the Ajax call will go into the DOM element with that ID.
def linkHandler():
...
content = CAT(SCRIPT(...), DIV(...))
return content
In linkHandler, instead of returning a dictionary (which requires a view in order to generate HTML), you can simply return a web2py HTML helper, which will automatically be serialized to HTML and then inserted into the target div. The CAT() helper simply concatenates other elements (in this case, your script and associated div).
One shouldn't have to ask this here, but thanks to the bad documentation, how do I access the querystring in a Spiffy (egg) app? Thanks!
(use intarweb spiffy sxml-serializer)
(tcp-buffer-size 2048)
(server-port 80)
(handle-not-found (lambda (path)
; (print (request-uri (current-request)))
; (print (request-method (current-request)))
; (print (current-pathinfo (current-request)))
; (print (current-file))
; (print (remote-address))
(send-response
body: (serialize-sxml
`(div (# (class "page"))
(h1 ,path))
method: 'html))))
(start-server)
I'm not exactly sure why you want to access the query string, but the
URI objects in Spiffy come from the request object, as you've correctly
identified. The request object is from intarweb, which sticks an
uri-common object in the request-uri attribute.
You can access the constituent component parts using uri-common's
accessors, as documented in the URI-common egg reference
The query string is parsed into an alist for your convenience, and
accessible through (uri-query (request-uri (current-request))).
The "original" query string can be accessed a little more differently:
the uri-common egg is a convenience wrapper around the lower-level egg
uri-generic, which you can access by calling (uri->uri-generic URI),
where URI is (request-uri (current-request)), as before.
Then, you can access the query string through the uri-query procedure
from that egg. Here's a simple example you can use on the REPL:
#;1> (use uri-common (prefix uri-generic generic:))
#;2> (uri-reference "http://foo?x=y")
#<URI-common: scheme=http port=#f host="foo" path=() query=((x . "y")) fragment=#f>
#;3> (uri-query #2)
((x . "y"))
#;4> (uri->uri-generic #2)
#<<URI>>
#;5> (generic:uri-query #4)
"x=y"
What I did here is prefix all the procedures from uri-generic with
"generic:". This is necessary because uri-common "shadows" all the
procedures defined by uri-generic.