How to call the second method

Hello,

I have this code of a challenge of learning clojurescript

(ns ^:figwheel-hooks learn-cljs.weather
  (:require
   [goog.dom :as gdom]
   [reagent.dom :as rdom]
   [reagent.core :as r]
   [ajax.core :as ajax]))


(defonce app-state (r/atom {:title "WhichWeather"          
                            :latitude 0
                            :longtitude 0
                            :zip-code "" 
                            :temperatures {:today {:label "Today"
                                                   :value nil}
                                           :tomorrow {:label "Tomorrow"
                                                      :value nil}}}))

(defn handle-response [resp]
  (let [today (get-in resp ["hourly" 1 "temp"])
        tomorrow (get-in resp ["hourly" 5 "temp"])]
    (swap! app-state
           update-in [:temperatures :today :value] (constantly today))
    (swap! app-state
           update-in [:temperatures :tomorrow :value] (constantly tomorrow))))

(defn handle-response-coordinates[resp]
   (let [lat (get-in resp ["coord" "lat"])
         lon (get-in resp ["coord" "lon"])]
     (swap! app-state
          update-in [:latitude] (constantly lat))
     (swap! app-state
           update-in [:longtitude] (constantly lon))))

(def api-key "fa9930ab5e2a87f9770d1c90d68f9da1")


(defn get-forecast! []                                     ;; <3>
  (let [lat (:latitude @app-state)
        lon (:longtitude @app-state)]
    (ajax/GET "http://api.openweathermap.org/data/2.5/onecall"
      {:params {"lat" lat
                "lon" long
                "units" "metric" ;; alternatively, use "metric"
                "appid" api-key}
       :handler handle-response})))

(defn get-coordinates []
  (let [zipcode (:zipcode @app-state)]
    (ajax/GET "http://api.openweatermap.org/data/2.4/weater"
     {:params {"q" zipcode
                "units"  "metric"
                "appid" api-key}
      :handler handle-response-coordinates})))


(defn title []
  [:h1 (:title @app-state)])

(defn temperature [temp]
  [:div {:class "temperature"}
   [:div {:class "value"}
    (:value temp)]
   [:h2 (:label temp)]])

(defn postal-code []
  [:div {:class "postal-code"}
   [:h3 "Enter your postal code"]
   [:input {:type "text"
            :placeholder "Postal Code"
            :value (:postal-code @app-state)
            :on-change #(swap! app-state assoc :postal-code (-> % .-target .-value))}]
   [:button {:on-click get-coordinates} "Go"]])

(defn app []
  [:div {:class "app"}
   [title]
   [:div {:class "temperatures"}
    (for [temp (vals (:temperatures @app-state))]
      [temperature temp])]
   [postal-code]])

(defn mount-app-element []
  (rdom/render [app] (gdom/getElement "app")))

(mount-app-element)

(defn ^:after-load on-reload []
  (mount-app-element))

but now I cannot find out where to call get-forecast after the handle-respons-coordinate method.
the get-forecast need the data provided by that handle

Looks like you could have handle-response-coordinates invoke it, or set up a watch via add-watch on the app-state, looking for changes in :lat and :lon keys.

oke, I did not learned that
Could you give me some hints how to achieve this ?

I try to invoke it but then get-forecast is not known and add-watch I did not learn so far.

I try to invoke it but then get-forecast is not known

You can move the definition of get-forecast! to before handle-reponse-coordinates, so you can invoke it from there. Alternately, you could invoke (declare get-forecast!) before handle-response-coordinates and invoke it inside handle-response-coordinates as if it exists, then define it later in the source. I typically prefer re-order the code instead of using declare though.

add-watch I did not learn so far

add-watch is a function that lets you register a “watch” function to any reference type (in this case, the app-state atom). You define a function that primarily cares about the old and new values, which then returns the “actual” new value to store in the atom. It is kind of like adding a change listener (or observer) to the atom. Something like this would be (granular) hook to look at changes to the latitude and longitude values and update the temperatures in the atom if they change:

(add-watch app-state  :forecast
    (fn [id atm old-val new-val]
         (when (and (not= (new-val :latitude) (old-val :latitude))
                    (not= (new-val :longitude) (old-val :longitude)))
           (get-forecast!))))

There are mixed feelings on this style; some project like re-frame try to provide tighter controls over the flow of changes to the app-state and any side-effects as a result. I think for your project it would probably be ok, just beware that you are entering into a sort of observer pattern that may not scale well.

1 Like

Thanks. I will try the first method without the declare thing.
Then I hope to find out why the get-coordinates is not returning anything.