Getting clientHeight from a react-reason DOM ref - dom

I'm accessing a reason-react DOM reference in order to ascertain client height.
Unfortunately clientHeight doesn't seem to be part of the ref API. So this fails:
ref
-> React.Ref.current
-> Js.Nullable.toOption
-> Belt.Option.map(this => {
React.Ref.clientHeight(this);
});
The value clientHeight can't be found in React.Ref.
Is there a way to extract the height of a component from the ref?
The ref was acquired from a div.

Assuming you acquired the ref from either ReactDOMRe.Ref.domRef or ReactDOMRe.Ref.callbackDomRef, you will receive a Dom.element and can use Element.clientHeight from bs-webapi:
open Webapi.Dom;
ref
-> React.Ref.current
-> Js.Nullable.toOption
-> Belt.Option.map(Element.clientHeight);

Related

how to use prevent default on Elm Browser.Event.onKeyDown

Please Note: I could not a find a solution that could work here, so I used ports for the same.
I need to use Browser.Events.onKeyDown for which I have also written a decoder, I need to create some shortcuts for my web app thus I need to prevent default behavior of Meta key (on Mac) and Ctrl key (on other Os)
In my Subscription method I am using the following.
But there is no exposed way of using prevent Default.
let
decoder : Decode.Decoder Msg
decoder =
keyDecoder
|> Decode.andThen
(\( keyCode, ctrlKey ) ->
case keyCode of
39 ->
Decode.succeed <| ShortCutNext
37 ->
Decode.succeed <| ShortCutPrevious
_ ->
Decode.fail ""
)
in
Sub.batch
[ Browser.Events.onKeyDown decoder]
keyDecoder : Decode.Decoder ( Int, Bool )
keyDecoder =
Decode.map2 (\a -> \b -> ( a, b ))
(Decode.field "keyCode" Decode.int)
(Decode.field "metaKey" Decode.bool)
Note: The event is on the page itself and not on any element such as textarea thus Html.Events.custom "keydown" options decoder is not applicable.

Combine Mono with every Flux element emitted

I have a Flux and Mono as below:
Mono<MyRequest> req = request.bodyToMono(MyRequest.class);
Mono<List<String>> mono1 = req.map(r -> r.getList());;
Flux<Long> flux1 = req.map(r -> r.getVals()) // getVals() return list of Long
.flatMapMany(Flux::fromIterable);
Now for each number in flux1, I want to call a method where params are the id from flux1 and the List<String> from mono1. Something like,
flux1.flatMap(id -> process(id, mono1))
But passing and processing same mono1 results in error Only one connection receive subscriber allowed. How can I achieve above? Thanks!
Since both information are coming from the same source, you could just run the whole thing with one pipeline like this and wrap both elements in a Tuple or better, a domain object that has more meaning:
Mono<MyRequest> req = // ...
Flux<Tuple2<Long, List<String>>> tuples = req.flatMapMany(r ->
Flux.fromIterable(r.getVals())
.map(id -> Tuples.of(id, r.getList()))
);
// once there, you can map that with your process method like
tuples.map(tup -> process(tup.getT1(), tup.getT2());
Note that this looks unusual, and this basically comes from the structure of that object you're receiving.

missing context in coffeescript => operator

App.WebNotificationComponent = Em.Component.extend
subscriptionQueue: null
connection: (->
App.StompConnection.create(subscriptionQueue: #get('subscriptionQueue'))
).property('subscriptionQueue')
willDestroy: ->
#get('connection').destroy()
App.AlertsIndexAlertWebNotificationComponent = App.WebNotificationComponent.extend
subscriptionQueue: "notifications"
didInsertElement: ->
#get('connection').onMessage = ((message) ->
result = JSON.parse(message.body)
App.AlertNotification.store.find('alert_notification', result.id).then (notification) =>
debugger
).bind(#get('targetObject'))
#get('connection').connect()
At the debugger breakpoint, I am no longer able to access message or result.
Is there anything that I am doing wrong or another way to do this ?
You can't access those values in the debugger because you didn't close over them, so they're not available in the closure. If you use them in the closure, they'll be available. Javascript has to know that you're going to use a variable in order to save it in the closed scope.
In other words, this will work as expected:
result = JSON.parse(message.body)
App.AlertNotification.store.find('alert_notification', result.id).then (notification) =>
console.log(message)
console.log(result)

Hiding Internal State of CoffeeScript Object

Looking at the following from CoffeeScript Ristretto:
QueueMaker = ->
do (queue = undefined) ->
array: []
head: 0
tail: -1
pushTail: (value) ->
queue.array[tail += 1] = value
pullHead: ->
unless queue.isEmpty()
do (value = queue.array[queue.head]) ->
queue.array[queue.head] = undefined
queue.head += 1
value
isEmpty: ->
queue.tail < queue.head
It's possible to mutate queue.head - http://jsfiddle.net/VQLNG/.
queue = QueueMaker()
queue.head = 666
console.log queue
How can I write the above function so that head isn't public?
JavaScript doesn't have private properties so CoffeeScript doesn't have them either.
However, you can simulate private properties in many cases by using function scopes to hide things and closures to access the hidden things.
A simple stack implementation should demonstrate the technique:
Stack = ->
stack = [ ]
push: (e) -> stack.push(e)
pop: -> stack.pop()
toArray: -> stack.slice()
stack is a local variable in the Stack function so it cannot be accessed or seen from outside Stack. The push and pop functions simply proxy to the stack array and the toArray function is the only way to see what stack looks like. Only those three functions have access to stack so it is effectively private and each time you call Stack, you get a new local stack.
Demo: http://jsfiddle.net/ambiguous/C8V5R/
Adapting your queue to use this technique to hide array, head and tail is left as an exercise.
The return value of QueueMaker is a JavaScript object, with head being one of it's fields. Object fields are mutable, with no option for protected status.
Even with QueueMaker rewritten as a CoffeeScript class, and head being an instance variable, it would still be mutable from outside the object scope.
CoffeeScript can only support the language level features of JavaScript, which does not support private/protected keywords. Sadly.
QueueMaker = ->
do (array = [], head = 0, tail = -1) ->
pushTail: (value) ->
array[tail += 1] = value
pullHead: ->
if tail >= head
do (value = array[head]) ->
array[head] = undefined
head += 1
value
isEmpty: ->
tail < head
With this version, array, head and tail are hidden. They are initialed when the queue is created, and remain in existence only as long as it exists.
coffee> queue = QueueMaker()
{ pushTail: [Function],
pullHead: [Function],
isEmpty: [Function] }
coffee> queue.head
undefined
But to be honest, this is the first version of QueueMaker on the Ristretto link. What you gave us was the “de-encapsulate” version, rewritten purposely to make these variables visible (in order to extend its behavior).
For reference, the "de-encapuslated" version is:
QueueMaker = ->
do (queue = undefined) ->
queue =
array: []
head: 0
tail: -1
pushTail: ...
pullHead: ...
Your question omitted the queue= line. Now the purpose of the do()-> should be clearer.

Can't get query results outside the function

I have this class in which i try to initialize array attributes with query results:
class data
minute: []
hour: []
constructor: () ->
findMin = events.find({"aggr":"minute"}).sort({$natural:-1}).limit(120)
findHour = events.find({"aggr":"hour"}).sort({$natural:-1}).limit(14)
findMin.execFind (errMin, resMin) ->
for recMin in resMin
#minute.push recMin
findHour.execFind (errH, resH) ->
for recH in resH
#hour.push recH
So i call smth = new data() and console.log smth and get an empty attributes and an error about undefined not having 'push' method. While i can understand an error i cant get why my arrays are empty. Dont get me wrong - i know this error causes them to be empty, but i tried several kinds of variants. And ive read about acync and callbacks, but still don't have a clue how to use callbacks not to 'alert' smth, but to use it afterwards. If you could help me with that or with some links that could - i would appreciate it SO much.
You have two issues. The one that is causing the error you are observing is that '#' inside of your two callbacks is not bound to your data instance, so you need to use =>. Secondly, and as pointed out by #AaronDufour, your hour and minute arrays are declared at the class level so they will be shared between every instance of data, which I doubt is what you want, so you need to move them into your constructor.
class data
constructor: () ->
#minute = []
#hour = []
findMin = events.find({"aggr":"minute"}).sort({$natural:-1}).limit(120)
findHour = events.find({"aggr":"hour"}).sort({$natural:-1}).limit(14)
findMin.execFind (errMin, resMin) =>
for recMin in resMin
#minute.push recMin
findHour.execFind (errH, resH) =>
for recH in resH
#hour.push recH
I assume you want minute and hour to be instance variables? They must be initialized in the constructor. The way you're doing it now, they're on the prototype, so it won't work properly. Try this:
class data
constructor: () ->
#minute = []
#hour = []
findMin = events.find({"aggr":"minute"}).sort({$natural:-1}).limit(120)
findHour = events.find({"aggr":"hour"}).sort({$natural:-1}).limit(14)
findMin.execFind (errMin, resMin) =>
for recMin in resMin
#minute.push recMin
findHour.execFind (errH, resH) =>
for recH in resH
#hour.push recH