Clojure - ajax.core POST - clojure

I am having some trouble with POST from ajax.
I want to add a user to my database, so I am using POST and the data I want to send is in the form {:id id :pass pass} This is my POST
(defn add-user! [user]
(POST "/add-user!"
{:params user}))
All I want to do is enter information in the form specified above into this POST so I can send it to the database. I know that the argument,to the POST, is in the right form and the queries to the database and my routes are correct but I've made a mistake with the POST and I cannot figure out my mistake.
I am calling add-user! by
(defonce fields (atom {}))
(defn add-user! [user]
(POST "/add-user!"
{:params user}))
(defn content
[]
[:div
[:div
[:p "Enter Name:"
[:input
{:type :text
:name :name
:on-change #(swap! fields assoc :id (-> % .-target .-value))
:value (:id #fields)}]]
[:p "Enter Pass:"
[:input
{:type :text
:name :pass
:on-change #(swap! fields assoc :pass (-> % .-target .-value))
:value (:pass #fields)}]]
[:input
{:type :submit
:on-click #(do
(add-user! #fields))
:value "Enter"}]]
[:div
[:p "Id is " (:id #fields)]
[:p "Pass is " (:pass #fields)]]])
My query to the database in a clj file is
(defn add-user! [user]
(sql/insert! db :users user))
where sql is [clojure.java.jdbc :as sql]

There is not really enough information here to help you debug this fully, but I suspect that you need to modify your POST to:
(defn add-user! [user]
(POST "/add-user!"
{:format :json
:params user}))
If you don't provide :format, cljs-ajax defaults to sending Transit data, which would definitely confuse a server expecting JSON.
:format - specifies the format for the body of the request (Transit, JSON, etc.). Also sets the appropriate Content-Type header. Defaults to :transit if not provided. - JulianBirch/cljs-ajax#getpostput

Happened to me with this code:
(POST "/admin/tests/load"
{:params {:test-id "83"}
:headers {"x-csrf-token" csrf-field}
:handler (fn [r] (do (.log js/console r) (swap! test-state r)))
:format :json
:response-format :json
:error-handler (fn [r] (prn r))})))
"params" always showed up empty "{}". Then I tried:
(POST "/admin/tests/load"
{:params {:test-id "83"}
:headers {"x-csrf-token" csrf-field}} )
and all started working well, even after adding the other options. I know, weird.

Related

Having problems with reagent atom and resert! function

Hi guys I'm new at Clojure and ClojureScript...
I'm filling out 2 select element ... What I wonna do is update the second select depending on what option the user choose in the first select.
This is my code:
(ns easy-recipe.components.calculate
(:require [reagent.core :as r :refer [atom]]
[ajax.core :as ajax]
[reagent.session :as session]
[easy-recipe.components.common :refer [input select button]]
[easy-recipe.bulma.core :refer [horizontal-select horizontal-input-has-addons table columns box]]))
(defn handler [request]
(session/put! :categories (get-in request [:body :categories]))
(session/put! :breads (get-in request [:body :breads]))
(session/put! :recipes (get-in request [:body :recipes])))
(defn error-hadler [request]
(let [errors {:server-error (get-in request [:body :erros])}]
errors))
(defn get-categories-breads-recipes []
(ajax/GET "/api/calculate"
{:handler handler
:error-hadler error-hadler}))
(defn select-fun-wrapper [breads]
(fn [e]
(let [category_value (-> e .-target .-value)]
(reset! breads
(filter
#(= category_value (str (% :category_id)))
(session/get :breads))))))
(defn calculate-page []
(get-categories-breads-recipes)
(let [fields (atom {})
categories (atom nil)
breads (atom nil)
recipe (atom nil)]
(fn []
(reset! categories (session/get :categories))
;(reset! breads (filter #(= 1 (% :category_id)) (session/get :breads)))
[:div.container
[box
[horizontal-select "Category"
[select "category" "select" #categories (select-fun-wrapper breads)]]
[horizontal-select "Bread"
[select "bread" "select" #breads #()]]
[horizontal-input-has-addons "Quantity"
[input "quantity" "input" :text "" fields]
[button "quantity-btn" "button" "Add" #() nil]]]
[box
[columns
[table ["Ingredients" "Quantity"] #recipe]
[table ["Product" " "] [["30 Panes" "x"]]]]]])))
As you have noticed the breads reset! is commented... now the "select-fun-wrapper" is working fine, it updates the bread select depening on the category option selected... but if I uncomment that line the "select-fun-wrapper" will stop working (not updating the second select)... I wonna know why does it happend?
I can not leave this line commented because right now I have the problem thar the "Bread" select starts empthy... How could I fill the bread atom without using the reset! function?
Extra code (if it makes it clear):
(ns easy-recipe.bulma.core)
(defn horizontal-select [label select]
[:div.field.is-horizontal
[:div.field-label.is-normal>label.label label]
[:div.field-body>div.field.is-narrow>div.control>div.select.is-fullwidth
select]])
....
(ns easy-recipe.components.common)
(defn select [id class options function]
[:select {:id id :class class :on-change function}
(for [opt options]
^{:key (opt :id)}
[:option {:value (opt :id)} (opt :name)])])
....

Lacinia-Pedestal GraphQL queries without args

I'm using lacinia+pedestal to set up a graphql service, most of the queries I've seen in the tutorial need an arg (iD) e.g. games_by_id, but I'd like to retrieve all objects without an arg:
(defn resolve-all-drivers
[drivers-map context args value]
drivers-map)
schema-data.edn
:all_drivers
{:type (list Driver)
:description "Get all the drivers"
:resolve :query/all-drivers}
}
schema:
:Driver {:description "A collection of drivers"
:fields {:id {:type (non-null ID)}
:name {:type (non-null String)}
:email {:type (non-null String)}}}
In GraphiQL:
{
all_drivers {
name
}
}
Any idea how I can change this to give me a whole list without args?
Updated the resolver map:
(defn resolver-map
[component]
(let [trips-data (-> (io/resource "trips-data.edn")
slurp
edn/read-string)
trips-map (entity-map trips-data :trips)
cars-map (entity-map trips-data :cars)
drivers-map (get trips-data :drivers)]
{:query/trip-by-id (partial resolve-trip-by-id trips-map)
:query/drivers-by-id (partial resolve-drivers-by-id drivers-map)
:query/all-drivers (partial resolve-all-drivers drivers-map)
:Trip/cars (partial resolve-trip-cars cars-map)
:Car/trips (partial resolve-car-trips trips-map)}))

How do I access individual fields of a form in Clojure?

I'm building my very first web app, and I am having a hard time accessing individual fields of a form when the user submits the form. Here's what I have:
(defroutes app
(GET "/" [] homepage)
(POST "/city" request display-city)
(route/resources "/")
(route/not-found "Not Found"))
(defn display-city [request]
(html5
[:div {:class "the-city"}
[:h2 "ALL ABOUT YOUR CITY"]
[:ul
[:li "Your city is " (str request) "! That's all"]]]))
;; and here's the hiccup form:
[:form {:action "/city" :method "post"}
(anti-forgery-field)
[:p "Enter your home address"]
[:div
[:label {:for "street-field"} "Street:"]
[:input {:id "street-field"
:type "text"
:name "street"}]]
[:div
[:label {:for "city-field"} "City:"]
[:input {:id "city-field"
:type "text"
:name "city"}]
[:div
[:label {:for "state-field"} "State:"]
[:input {:id "state-field"
:type "text"
:name "state"}]
[:label {:for "zip-field"} "ZIP:"]
[:input {:id "zip-field"
:type "text"
:name "zip"
:size "10"}]]
[:div.button
[:button {:type "submit"} "Submit"]]]])
;; When I run the code above, I can see the entire form that's submitted via (str request), in what looks to be a Clojure map. But I can't figure out how to extract individual "key/vals" (from that address form, I'd like to extract the city), or how to store those results in a way that I can use it. Any ideas?
This is a super basic /city page that I am trying to get running to understand how things work before building bigger things. Thanks!
In your request map, there should be a key :form-params with a map of key/value pairs that were POSTed. Here's how you could get an individual value out:
(get-in request [:form-params :city])
Or you could destructure :form-params map to bind many values at once:
(let [{:keys [city state zip]} (:form-params request)]
(format "%s, %s %s" city state zip))

Simple Clojurescript form

I'm working with Reagent and CLJS, familiar with React and Clojure, less so CLJS. I'd like to make a simple form, but it's not obvious to me in CLJS.
(defn form []
[:div
[:input {:type "text" :name "first-name" :id "first-name"}]
[:button {:on-click (fn [e] (test-func "hello"))}
"Click me!"]
])
I want to grab the value of that input, and pass it to a function when the button is clicked. How do I get that input's value into my on-click function?
The idiomatic and technically correct way is to avoid keeping any state in DOM and accessing it directly. You shouldn't rely on the input's value. Keep the state as Reagent's atom. Then you can do anything with it.
(def first-name (r/atom ""))
(defn form []
[:div
[:input {:type "text"
:value #first-name
:on-change #(reset! first-name (.-value (.-target %)))
}]
[:button {:on-click #(test-func #first-name)} "Click me!"]])
You can grab the element's value like this: (.-value (.getElementById js/document "first-name"))
(defn form []
[:div
[:input {:type "text" :name "first-name" :id "first-name"}]
[:button {:on-click (fn [e] (test-func (.-value (.getElementById js/document "first-name"))))}
"Click me!"]
])
If there is a better answer out there, please share. :)

Number format exception in compojure

As total clojure noob, I am trying to start one small tutorial app, in order to get familiar with compojure. It's a small application which lets user add two numbers, and after clicking on button displays their sum on the other page. I followed instruction from Mark McGranaghan blog. Everything seems ok, until I try to get sum of two numbers I have entered, instead of getting result, I am redirected to the same page (so basically I am stuck on first step of this tutorial). After checking the code, it seems that NumberFormatException is triggered when input parsing takes place (for some reason). In all my tests, I have tried to input all kinds of number format , but with no success. Here is the simplest code version , for which author said should work (I have tried the latest version from github site- same scenario: NFE):
(ns adder.core
(:use compojure.core)
(:use hiccup.core)
(:use hiccup.page-helpers))
(defn view-layout [& content]
(html
(doctype :xhtml-strict)
(xhtml-tag "en"
[:head
[:meta {:http-equiv "Content-type"
:content "text/html; charset=utf-8"}]
[:title "adder"]]
[:body content])))
(defn view-input []
(view-layout
[:h2 "add two numbers"]
[:form {:method "post" :action "/"}
[:input.math {:type "text" :name "a"}] [:span.math " + "]
[:input.math {:type "text" :name "b"}] [:br]
[:input.action {:type "submit" :value "add"}]]))
(defn view-output [a b sum]
(view-layout
[:h2 "two numbers added"]
[:p.math a " + " b " = " sum]
[:a.action {:href "/"} "add more numbers"]))
(defn parse-input [a b] ;; this is the place where problem occures
[(Integer/parseInt a) (Integer/parseInt b)])
(defroutes app
(GET "/" []
(view-input))
(POST "/" [a b]
(let [[a b] (parse-input a b)
sum (+ a b)]
(view-output a b sum)))
Can anyone tell me better way to pars the input values, in order to avoid this exception?I have tried couple of techniques , but nothing worked for me. I am using Leningen v1.7.1 with clojure 1.3 on win 7 machine.
Here is content of my project.clj file:
(defproject adder "0.0.1"
:description "Add two numbers."
:dependencies
[[org.clojure/clojure "1.3.0"]
[org.clojure/clojure-contrib "1.1.0"]
[ring/ring-core "1.0.2"]
[ring/ring-devel "1.0.2"]
[ring/ring-jetty-adapter "1.0.2"]
[compojure "1.0.1"]
[hiccup "0.3.8"]]
:dev-dependencies
[[lein-run "1.0.0"]])
and run.clj script:
(use 'ring.adapter.jetty)
(require 'adder.core)
(let [port (Integer/parseInt (get (System/getenv) "PORT" "8080"))]
(run-jetty #'adder.core/app {:port port}))
Thanks.
You are using compojure 1.0.1, the example in the blog you are following is using compojure 0.4.0.
As of version 0.6.0, Compojure no longer adds default middleware to routes. This means you must explicitly add the wrap-params and wrap-cookies middleware to your routes.
Source: https://github.com/weavejester/compojure
So you need to explicitly add the wrap-params middleware. So the following changes are required...
(ns adder.core
(:use ; change to idiomatic usage of :use
[compojure.core]
[hiccup.core]
[hiccup.page-helpers]
[ring.middleware.params :only [wrap-params]])) ; add middleware for params
(defn view-layout [& content]
(html
(doctype :xhtml-strict)
(xhtml-tag "en"
[:head
[:meta {:http-equiv "Content-type"
:content "text/html; charset=utf-8"}]
[:title "adder"]]
[:body content])))
(defn view-input []
(view-layout
[:h2 "add two numbers"]
[:form {:method "post" :action "/"}
[:input.math {:type "text" :name "a" :id "a"}] [:span.math " + "]
[:input.math {:type "text" :name "b" :id "a"}] [:br]
[:input.action {:type "submit" :value "add"}]]))
(defn view-output [a b sum]
(view-layout
[:h2 "two numbers added"]
[:p.math a " + " b " = " sum]
[:a.action {:href "/"} "add more numbers"]))
(defn parse-input [a b]
[(Integer/parseInt a) (Integer/parseInt b)])
(defroutes main-routes ; needs to be renamed
(GET "/" []
(view-input))
(POST "/" [a b]
(let [[a b] (parse-input a b)
sum (+ a b)]
(view-output a b sum))))
(def app (wrap-params main-routes)) ; wrap the params to allow destructuring to work