port module for JS interop.. without main/view ?

204 views
Skip to first unread message

Jörg Winter

unread,
Jul 23, 2016, 6:20:26 PM7/23/16
to Elm Discuss
So I have this port module which lets me invoke elm-actions from JS and get back results into JS
(Basically I just want to use this elm module like a library of elm functions, no Html rendering needed!)

It seems I have to give it a main function and use Html.App.program, which in turn requires me to define a view function.

Is there any way to expose ports to JS -without- defining a full blown main + view ?
Just using Elm for implementing a library ?

Nick H

unread,
Jul 23, 2016, 7:12:17 PM7/23/16
to elm-d...@googlegroups.com
This page of the guide mentions a way of running an Elm program as a "worker," where there is no UI. Would that work for you?(In that case I am guessing you could just provide an empty view function.)


--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jörg Winter

unread,
Jul 24, 2016, 6:06:09 AM7/24/16
to Elm Discuss
That is exactly what I did in Js ... I calLed that worker() function, assuming there was no requirement to have a view.
Yet elm was complaining when I removed the view function from my (port) module.

view is required in Html.App.program

Removing main entirely does not work either.. elm just won't run anything in that case.


art yerkes

unread,
Jul 24, 2016, 4:21:31 PM7/24/16
to Elm Discuss
You do need a main, at the very least to pass init, update and subscriptions to the runtime that will iterate your app.  View can return a single DOM node and be satisfied.  It won't actually be displayed, but needs to be there.

Elm works well in this scenario.  Here's an example I did a while back:

Jörg Winter

unread,
Jul 24, 2016, 5:19:30 PM7/24/16
to Elm Discuss
Hey thanks for that blog-post about this use-case, exactly what I aimed for initially.

Meanwhile I discovered that the Elm.embed(node) interop-variant actually makes sense for me.... so I can use Elm's view afterall.
Works great so far.

Luke Westby

unread,
Jul 25, 2016, 11:29:32 PM7/25/16
to Elm Discuss
In the event that you want to use Elm.MyModule.worker() in the future, this module will let you set things up without worrying about the view part http://package.elm-lang.org/packages/lukewestby/worker/latest

Jörg Winter

unread,
Jul 26, 2016, 3:10:09 AM7/26/16
to Elm Discuss
Great.
That example shows only subscribing/receiving from Elm but not sending any input to Elm.

Could you post an example showing send + subscribe ?
Maybe such a Elm call (send with result) could be packaged a a JS promise too (?)

Luke Westby

unread,
Jul 26, 2016, 9:17:51 AM7/26/16
to Elm Discuss
Sure! Here's a gist containing such an example: https://gist.github.com/lukewestby/4983afbec4e0851db165d8298de05053

As far as wrapping things in a Promise, I think you would have better luck wrapping things up in an Observable. Ports going into and coming out of an Elm application are continuous, whereas we know Promises to be singular. It would take a bit of extra effort to be able to identify which call to `send` is responsible for which result from `subscribe`. It is possible, but using an Observable interface here might work better.
Message has been deleted

Jörg Winter

unread,
Jul 26, 2016, 3:34:53 PM7/26/16
to Elm Discuss
Thanks!

Guess you mean somehow combining (join, merge..) 2 Observables (sending + receiving to/from a port) to correlate the request(=send) with the reply(=subscribe-callback) ?

Yonatan Kogan

unread,
Jul 26, 2016, 6:44:28 PM7/26/16
to elm-d...@googlegroups.com
We're doing this at work and I've strongly considered writing some promise layer (disclaimer: I know nothing about observables). I was going to do this by building a javascript module to manage the interface between JS and elm that would assign every message into elm a unique ID (monotonically increasing counter that's module-scoped in JS) and then have elm write out it's response along with the unique id. The JS module moderating the interface could then look up the promise it had returned by id and resolve / reject it as needed. I think this could be done pretty cleanly on the elm side as well by enforcing that both input and output ports have a type that's something like

```
type portMessage =
  { id : Int
  , message: Json.Decode.Value
  }
```

On Tue, Jul 26, 2016 at 2:34 PM, Jörg Winter <jwin...@gmail.com> wrote:
Thanks!

Guess you mean somehow combining (join, merge..) 2 Observables (sending + receiving to/from a port) to correlate the request(=send) with the reply(=subscribe-callback) ?

--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Yonatan Kogan

Jörg Winter

unread,
Jul 27, 2016, 11:57:57 AM7/27/16
to elm-d...@googlegroups.com

Do you think a correlating by Id is necessary ?
If it is the simple case of having only 1 inbound and 1 outbound port in Elm and doing nothing async in Elm ... isn't a send/receive in JS basically synchronous ?

A promise could still make sense but that Id would not be necessary.

Some explanation in the Elm Guide would help a lot here.

Jörg Winter

unread,
Jul 27, 2016, 1:36:33 PM7/27/16
to Elm Discuss
Just to clarify, I talk about calling Elm from JS.

Yonatan Kogan

unread,
Jul 27, 2016, 9:44:27 PM7/27/16
to elm-d...@googlegroups.com
For us, we have multiple inbound ports and some outbound ports (inbound to elm from js, outbound to js from elm) so it's more useful.

The send from Elm to JS is synchronous (newly in 0.17 I believe?) but going from JS to Elm is not, as it seems like Elm waits until nextTick to pick up the message (understandably). We still want to be able to say "after elm has processed this" though. The analogy would be "after this Ajax request has returned," so a Promise interface seems to make sense (again, I know nothing about Observables).

I don't think this is stable, but it does seem like the following is effectively the same:

```js
elmApp.ports.portName.send(message);
setTimeout(function() {
  // use newly updated data
});
```

Also, writing that code highlights for me that our need is somewhat specific to elm updating a redux/flux store and we then want to take action on the updated store.

On Wed, Jul 27, 2016 at 12:36 PM, Jörg Winter <jwin...@gmail.com> wrote:
Just to clarify, I talk about calling Elm from JS.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Yonatan Kogan

Leroy Campbell

unread,
Jul 28, 2016, 5:09:03 PM7/28/16
to Elm Discuss
Just to clarify, inbound messages to Elm are batched (enqueued) and then executed on nextTick.

And to echo Luke, observables would make more sense. A Promise-based interface would mean supporting only request-response semantics. Observables not only allow for request-response, but also publish-subscribe semantics.

For example, suppose you have an Elm worker that processes stock tickers. You send an inbound message to subscribe to one or more ticker symbols. An outgoing port would continue to stream updates until you send a message to unsubscribe from a particular ticker symbol (or all). I'm not sure how you'd pull that off with Promises.
Reply all
Reply to author
Forward
0 new messages