This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-27
Channels
- # announcements (2)
- # asami (25)
- # babashka (124)
- # beginners (46)
- # calva (55)
- # cljdoc (70)
- # clojure (68)
- # clojure-australia (2)
- # clojure-dev (63)
- # clojure-europe (38)
- # clojure-nl (1)
- # clojure-spec (1)
- # clojure-uk (8)
- # clojurescript (56)
- # community-development (4)
- # conjure (1)
- # copenhagen-clojurians (1)
- # core-async (1)
- # cursive (3)
- # datahike (5)
- # datomic (183)
- # depstar (2)
- # figwheel-main (10)
- # fulcro (20)
- # honeysql (2)
- # hyperfiddle (1)
- # integrant (68)
- # jobs (6)
- # jobs-discuss (5)
- # juxt (1)
- # malli (13)
- # off-topic (8)
- # pathom (2)
- # rdf (10)
- # reagent (11)
- # remote-jobs (1)
- # rum (1)
- # shadow-cljs (69)
- # spacemacs (1)
- # sql (5)
- # tools-build (51)
- # tools-deps (6)
- # xtdb (24)
I have a production and a development environment, but I don’t understand this: This is my code:
(let [provider
(new (.. ethers -providers -Web3Provider)
(.-ethereum js/window) "any")
_ (js/console.log "provider is " provider)
contract (try
(new (.. ethers -Contract)
address
(.-abi (js/JSON.parse contract-json))
provider)
(catch js/Object e (prn "error:" e)))
_ (js/console.log "contract is " contract)
amount (try (<p! (.. contract (totalAmountRaised)))
(catch js/Object e (prn "error:" e)))]
(prn "amount is " amount)
(dispatch [:set-total-amount-raised amount]))
In development it works file and I see the prn “amount is ” #object[BigNumber 107250000000000000]. But when I deploy this on google cloud gke, I see the following for the same code:
The exception is catched:
"error:" #object[TypeError TypeError: p.ql is not a function]
and “amount is ” niland looking at the app.js code for p.ql doesn’t really do me any good
Your production code is minimized. When you use JS interop, you gotta know which fields can and cannot be renamed. Those should correspond 1-to-1 to the fields that should and should not be renamed. Externs help with that. There are multiple resources on externs, but these two should give you what you need: • https://clojurescript.org/guides/externs • https://code.thheller.com/blog/shadow-cljs/2017/11/06/improved-externs-inference.html
so I added ^js tags on provider and contract, but I still see the warning
Cannot infer target type in expression (. inst_61399 (totalAmountRaised))
This is what I have now:
[provider
^js (new (.. ethers -providers -Web3Provider)
(.-ethereum js/window) "any")
_ (js/console.log "provider is " provider)
contract ^js (try
(new (.. ethers -Contract)
address
(.-abi (js/JSON.parse contract-json))
provider)
(catch js/Object e (prn "error:" e)))
_ (js/console.log "contract is " contract)
amount (try (<p! (.. contract (^js totalAmountRaised)))
(catch js/Object e (prn "error:" e)))]
You have to add ^js
in front of every expression which type cannot be inferred. I assume in this case it's inst_61399
.
If you have forms like ..
, then I think you have to add ^js
in between the forms.
If you still can't figure it out with all that in mind, just split all JS field accesses and function calls into separate unchained expressions, and see which are missing ^js
.
inst_613199 is contract, and there’s already a ^js there
also I’ve heard that ^js doesn’t work so well inside go
that might be the cause
Also, add ^js
to the symbol and not to the form that you assign to the symbol. So it should be ^js contract (...)
. I think both work, but this is proper and makes you think in the right plane.
^js
does not work inside go
at all. You can extract all functionality that uses ^js
in a separate function and use that function within go
- it'll work.
How can I setDatasource in clojurescript using javascript interlop onGridReady = params => {
this.gridApi = params.api;
this.gridColumnApi = params.columnApi;
const httpRequest = new XMLHttpRequest();
const updateData = data => {
var dataSource = {
rowCount: null,
getRows: function(params) {
console.log("asking for " + params.startRow + " to " + params.endRow);
setTimeout(function() {
var rowsThisPage = data.slice(params.startRow, params.endRow);
var lastRow = -1;
if (data.length <= params.endRow) {
lastRow = data.length;
}
params.successCallback(rowsThisPage, lastRow);
}, 500);
}
};
params.api.setDatasource(dataSource);
};
It will be easier to answer your question if you use proper code block formatting. Also, there are many resources on JS interop - guides, examples, cheatsheets, etc. What have you tried so far?
onGridReady = params => {
this.gridApi = params.api;
this.gridColumnApi = params.columnApi;
const httpRequest = new XMLHttpRequest();
const updateData = data => {
var dataSource = {
rowCount: null,
getRows: function(params) {
console.log("asking for " + params.startRow + " to " + params.endRow);
setTimeout(function() {
var rowsThisPage = data.slice(params.startRow, params.endRow);
var lastRow = -1;
if (data.length <= params.endRow) {
lastRow = data.length;
}
params.successCallback(rowsThisPage, lastRow);
}, 500);
}
};
params.api.setDatasource(dataSource);
};
httpRequest.open(
"GET",
""
);
httpRequest.send();
httpRequest.onreadystatechange = () => {
if (httpRequest.readyState === 4 && httpRequest.status === 200) {
updateData(JSON.parse(httpRequest.responseText));
}
};
};
I am trying to implement onGridReady and in console when I print params I get this {:type gridReady, :api #object[a [object Object]], :columnApi #object[a [object Object]]}
So what's the problem?
In JS, params.api
gets the value of the field api
from the object referenced by params
. In CLJS, (:api params)
gets the value of the key :api
from the map referenced by params
.
(defn set-datasource [params data]
(let [paramsData (js->clj params :keywordize-keys true)]
(println (js->clj (get-in paramsData [:api :setDatasource]) :keywordize-keys true))
(swap! paramsData update-in [:api :setDatasource] { "getRows" (fn [event]
(println event)
(let [eventData (js->clj event :keywordize-keys true)
endRow (get-in eventData [:endRow])
startRow (get-in eventData [:startRow])
]
(println (str "startrow" startRow))
(println (str "edrow" endRow)))
)
})))
If it works then good, but you don't need to use js->clj
- you can just use JS interop. It's more direct, less error-prone, and more efficient because there will be no data conversion.
"onGridReady" (fn [params]
(let [data (get-data)] (.. js/params -api setDatasource { "getRows" (fn [event] (println event) (let [eventData (js->clj event :keywordize-keys true) endRow (get-in eventData [:endRow]) startRow (get-in eventData [:startRow]) ] (println (str "startrow" startRow)) (println (str "edrow" endRow))) )})))
No clue, because: • There are many more factors outside of this tiny snippet of code • Your didn't put any effort in formatting the code, so it's completely unreadable
first i am getting data from API and then trying to setDatasource for (fn [params] ) like
js/params
takes the value of a global JS variable named param
. You need just param
since that's what you pass into your onGridReady
function.
setDatasource
, being a JS function, probably expects a JS object as its argument, but you're passing a CLJS map. Add #js
in front of that opening {
.
okay, am I calling it right because I am getting error as Caused by: java.lang.Error: Unknown dot form of (. (. (. params -api) setDatasource) #object[cljs.tagged_literals.JSValue 0x6422aaf6 "cljs.tagged_literals.JSValue@6422aaf6"] nil)
used it I am getting Uncaught TypeError: Cannot read property 'setDatasource' of undefined
^js
is necessary for the right externs inference during the production build, so that api
or setDatasource
names are not mangled.
It's not needed in development, but won't hurt.
Do I need to use goog.object/getValueByKeys to get api first and than user setDatasource ?
@U2FRKM4TW This worked
(.setDatasource (goog.object/getValueByKeys params #js ["api"]) (clj->js {:getRows (fn [event])}))
That's exactly what ^js
is for.
Could be rewritten as
(.. ^js params -api (setDatasource #js {:getRows (fn [event])}))
You might need to add an extra ^js
in there if that doesn't work in production due to setDatasource
being renamed.Just tested - one ^js
is enough. And ideally, it should be added right where you bind the value to a new name, to the function signature should be [^js params]
instead of just [params]
- then any access to the fields within params
, even nested ones, should work just fine in production.
@U2FRKM4TW trying to replicate something like this https://clojurians-log.clojureverse.org/reagent/2020-10-26
Yet again - you're missing ^js
somewhere.
Read about externs. These are good resources:
• https://clojurescript.org/guides/externs
• https://code.thheller.com/blog/shadow-cljs/2017/11/06/improved-externs-inference.html
(.successCallback ^js params (clj->js (get-in data-json [:data])) (clj->js (get-in params [:endRow])))
I am calling like thisThat's just one line from your code. I don't know what makes you sure that it's the line that causes the problem. I have provided you with everything I knew that's relevant to the topic, including the links for further reading. The rest is up to you.