These are chat archives for jdubray/sam

24th
Jun 2016
Edward Mulraney
@edmulraney
Jun 24 2016 14:42
@jdubray/anyone: in SAM, is it right to say control state determines the view. e.g. state.ready, state.started, etc. maps to view.ready, view.started?
Edward Mulraney
@edmulraney
Jun 24 2016 14:51
state shouldnt be global like all the examples, it should be local to a component right?
Jean-Jacques Dubray
@jdubray
Jun 24 2016 14:55
@edmulraney It's not mandatory to reason that way, this is just on example. I don't think we need to be too prescriptive
State can be decomposed from global to local (say from page/view down to how the component at this moment in time appear in that view)
I was looking at a React implementation of the Rectangle:
http://browniefed.com/blog/react-art-zooming-and-dragging/
That's where you see how flawed a pre-wired stateful component can be, compared to a stateless / single state tree architecture (I don't want to say just SAM).
Edward Mulraney
@edmulraney
Jun 24 2016 14:59
for sure
re: states/views, it seems to make most sense then if we give components their own state and view capability
for general web app development
i mean the SAM definition of state and view
control state
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:11

their own state and view capability

just a word of caution, components must be 100% unless we are talking about "config parameters"

State function -> What gets displayed
View -> Where it gets displayed
Theme -> How it gets displayed

I am actually refactoring the rectangle example with a proper theme/view
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:17
For instance the "net" components takes two arguments from the state representation:
net: (ctx, canvas, net, fishes) => {
         // draw the net
        net.rect(ctx,canvas) ;
        if (fishes>0) {
                var _fishes = (fishes>1)? ' fishes!' : ' fish' ;
                net.caught.innerHTML = " you caught "+fishes+_fishes ;
            } else {
                net.caught.innerHTML = "" ;
        }
    }
the views display the net with that call:
theme.net(this.ctx,this.canvas,
       { rect: stateRepresentation.rect, caught: this.net },
      stateRepresentation.fishes) ;
Edward Mulraney
@edmulraney
Jun 24 2016 15:20
"View -> Where it gets displayed"
Does this mean where the component gets mounted? e.g. document.getElementById("blah").innerHTML = component(...)
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:20
That's how I do it
Edward Mulraney
@edmulraney
Jun 24 2016 15:21
what if you dont know where the component should be mounted? e.g. i have one hundred rectangles on one page
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:21
The view knows where the components are:
var view = (function(canvas,net) {
...
})(document.getElementById('canvas'),document.getElementById('net')) ;
Well, ultimately a component renders somewhere. Do you see an alternative? what do you have in mind?
Edward Mulraney
@edmulraney
Jun 24 2016 15:22
that's fine for a contrived example where you're mounting to a specified element. but your app in real life wont have these elements defined. your app in real life will be:
<div id="app"></div>
the elements have to be generated dynamically
you have an initial view
then navigation/actions allow you to see different components. which could be components composed of components
we can't hard code these things
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:23
I don't view it as incompatible. Let me try to refactor the example with that in mind.
I agree, they are generally not hard coded.
Edward Mulraney
@edmulraney
Jun 24 2016 15:41
i noticed the todomvc example state has state.render which calls the view.display, whereas the tic-tac-toe engine, only has control states - no reference to the view, no state.render
what exactly is the state function?
it seems like an anti-pattern to wire a control state to a view
wouldnt it be better to pass in the control-state as a prop to the view-component and let the view-component decide how it should render itself, based off the current control state?
Edward Mulraney
@edmulraney
Jun 24 2016 15:48
so we still have control state, but we no longer have state.representation() with manually wired control-state views. we have a single view.render(props) with controlState in the props or as an arguments
e.g.
    if (state.ready(model)) {
        representation = state.view.ready(model) ;
    } 

    if (state.counting(model)) {
        representation = state.view.counting(model) ;
    }

    if (state.launched(model)) {
        representation = state.view.launched(model) ;
    }

    if (state.aborted(model)) {
        representation = state.view.aborted(model) ;
    }
becomes
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:50
The idea is to leave some interpretation, I feel that making everything a "control state" (in the sense of state machines) is too prescriptive.
Yes, I have evolved a bit since that example.
Edward Mulraney
@edmulraney
Jun 24 2016 15:51
return display(currentState)
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:51
The State function computes the State Representation and NAP()
devin ivy
@devinivy
Jun 24 2016 15:52
@jdubray might each view have its own state representation? is this akin to redux's connect() / mapStateToProps?
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:52
The State representation can be:
  • some json
  • some HTML
  • a function that gets executed (such as draw rectangle)
  • anything else?
Edward Mulraney
@edmulraney
Jun 24 2016 15:52
for it to scale each view would need its own state representation as @devinivy says
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:53
The problem with Redux is React's Reactive model, you need to "connect" views and models/store
devin ivy
@devinivy
Jun 24 2016 15:53
right, but you don't have to connect the store directly
Edward Mulraney
@edmulraney
Jun 24 2016 15:53
but you dont really have to "connect" anything
devin ivy
@devinivy
Jun 24 2016 15:53
you can write a function that maps the store to properties for use in the component.
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:53

each view would need its own state representation

yes, it's not different from what I am saying (I think)

Edward Mulraney
@edmulraney
Jun 24 2016 15:53
in SAM you literally have to connect everything manually, in redux you dont
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:54
SAM is not a framework, it is a pattern, you can use React/Redux and still implement SAM
devin ivy
@devinivy
Jun 24 2016 15:54
right! :)
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:55
I am trying to show how SAM works in Vanilla.js so that it's common to everyone
Edward Mulraney
@edmulraney
Jun 24 2016 15:55
yes, what i'm feeling tho is that when you start to put SAM into a framework, you end up with redux
just with some minor differences
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:55
not exactly, yes, but these "minor" differences are not so minor
Edward Mulraney
@edmulraney
Jun 24 2016 15:55
I'll keep playing with it, I will have an app example soon hopefully
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:56
Redux is clearly the closest to SAM by far, but still I have not been able to communicate with the Redux community about SAM's semantics.
I am not the only one for instance to think that an immutable model is not the right way to go
Edward Mulraney
@edmulraney
Jun 24 2016 15:57
i think showing SAM in vanilla is definitely the right way to go, but the vanilla examples so far don't make it easy to look at and say "ah that's SAM!"
devin ivy
@devinivy
Jun 24 2016 15:57
i think seeing SAFE in redux-land would do a whole lot of good.
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:57
yes, me too. Concepts like "allowed actions" and "action hand back" would be very handy
The message I am trying to convey is that semantics matter
  • what is an action
  • is the model immutable
  • where you do you hook API calls?
  • Are Sagas equivalent to NAP() ?
devin ivy
@devinivy
Jun 24 2016 15:59
if you take redux and add nap() middleware, call the store the "model", use thunks for actions, and use connect()'s mapStateToProps liberally, you start to see SAM arise.
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:59
All these questions lead to non trivial changes in your code
devin ivy
@devinivy
Jun 24 2016 15:59
using a mutable store in react is going to be hard, i'd guess.
Jean-Jacques Dubray
@jdubray
Jun 24 2016 15:59
@devinivy yes, I agree.
devin ivy
@devinivy
Jun 24 2016 15:59
but not in redux on its own.
Edward Mulraney
@edmulraney
Jun 24 2016 15:59
this is what I've been feeling
redux in the real world is SAM. at least, what I've seen and used of it
perhaps slightly different approach to nap() but not significantly different
devin ivy
@devinivy
Jun 24 2016 16:00
except i don't often see nap()...
right
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:00
yes, so why not be more prescriptive?
well it depends on what you need to do, when you need nap() it comes very handy
Look at what redux is doing with API calls, forcing people to use Sagas?
This is insane
Edward Mulraney
@edmulraney
Jun 24 2016 16:01
yeah i think sagas is not a great solution. or redux-loop. but perhaps my use case of needing next-action has been biased
devin ivy
@devinivy
Jun 24 2016 16:01
yeah, it's pretty wild. equally reflected in that "what to do about effects" issue on github. the proposed answer was to wait for "algebraic effects" to be part of javascript.
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:01
If SAM can help people use Redux in a more streamlined way, I am all for it
devin ivy
@devinivy
Jun 24 2016 16:02
similarly sagas rely heavily on ES6 generators and async/await
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:02
I want to be very clear, I am not trying to build my own Framework, SAFE is just here to illustrate some concepts that are enabled with SAM
Edward Mulraney
@edmulraney
Jun 24 2016 16:02
yeah i think introducing generators to solve the problem is too much
ah. @jdubray that makes more sense now. i naturally thought you were trying to promote a new framework (or eventually)
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:03
no, I am not of that caliber, I'll never try that.
I do find it interesting that it's really difficult to start a discussion on semantics. Even with Mendix who is one of the most accomplished Model-Driven framework,ever, therefore they pay a lot of attention to their semantics.
Edward Mulraney
@edmulraney
Jun 24 2016 16:07
i suppose it's difficult to engage in conversation on that because it's currently hard to see exactly what benefits the semantics your suggesting bring
it's easier to work with compelling practical examples that demonstrate SAM solving a problem we experience with, rather than reasoning in theoretical optimums
maybe thats just me
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:10
Well, there is a theory behind code, ignore it at your own risk. After all, they are pushing FRP without compelling evidence that it is solving a problem we experience.
I love to apply functional/reactive principles wherever I can, but not beyond what they can achieve.
Edward Mulraney
@edmulraney
Jun 24 2016 16:12
yeah that's true, that's why I'm pursuing SAM
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:12
thank you, happy to answer any question you have.
Edward Mulraney
@edmulraney
Jun 24 2016 16:18
it seems like it would be better if, when we .present() a proposal to the model, we also give it an identifier, so the model knows what we're trying to do
currently in the examples, the model has to do some kind of conditional check to try and work out what the proposal is
and then we perform a mutation
we could define a mutation based on an identifier and remove the need for conditional checks
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:19
I agree, the idea though is that it is not an "action" it is an "update" in other words a "unit of work"
as I mentioned before there is a many-action-to-one-unit of work relationship
what I really don't like with Redux is that the Reducer switches on "actions", that's a recipe for disaster.
You can have dozens, hundreds of actions, but 5-10x less "units of work"
Edward Mulraney
@edmulraney
Jun 24 2016 16:20
present is independent from actions which is good
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:21
yes, my point all along with Redux and the reducer.
The business logic coded in the actions is focused on the task at hand while the one in the model is focused on a much broader scope, keep the integrity of the application state.
Edward Mulraney
@edmulraney
Jun 24 2016 16:24
so what would a suitable identifier be for you?
present({identifier: "NEW_RECTANGLE", data: {...}})
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:26
yes, that sounds reasonable, as we discussed before the action translate events into units of work (such as create a new rectangle)
Then you can wire many different actions which would want to create a new rectangle, for instance you could create a new action that does not work on drag, just on mouse click and then generates the size of the rectangle randomly
that would be very easy to add such an action with SAM
I am just trying to say that this factoring is not "random", I didn't even come up with it, I use TLA+ semantics.
Edward Mulraney
@edmulraney
Jun 24 2016 16:48
i guess we'd want some sort of consistency in the structure of the proposal we present? otherwise it would be difficult to reason about what is going to be proposed, and interoperability with other apps/libraries
some sort of identifier, and a payload?
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:53
yes, totally agree
It's like calling a service
Edward Mulraney
@edmulraney
Jun 24 2016 16:54
{
  type: "blah",
  payload: {
      ...
   }
}
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:54
yes
Edward Mulraney
@edmulraney
Jun 24 2016 16:54
cool
Jean-Jacques Dubray
@jdubray
Jun 24 2016 16:54
Again, I am trying to be not too prescriptive, a framework would do that.
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:17
What's not shown here well is the "wiring" of the elements of the pattern, I use global variables, which is not ideal (for instance the theme is initialized in the view, which is not ideal by any means).
Edward Mulraney
@edmulraney
Jun 24 2016 17:27
nice
You have no particular preference to how it would be wired together?
there's no reason why present has to be inside the model, it just needs a reference to the model
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:30
absolutely
Edward Mulraney
@edmulraney
Jun 24 2016 17:30
as long as the immediate action following present is state.render
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:30
SAFE includes a wiring function since it is a middleware
SAFE:
var actions = require('./actions') ;  
var model = require('./model') ;
var view = require('./view') ;
var state = require('./state') ;

var safe = require('sam-safe') ;

safe.init(actions,model,state,view) ;
Edward Mulraney
@edmulraney
Jun 24 2016 17:32
and all state.render has to do is return the component markup, and call the nap
so you'd be happy with an api that was like
present(modelRef, proposal)
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:34
Sure, conceptually you can break down the model into logical units and even have more than one present method, as long as you keep the flow "proposer/acceptor/learner" and you make sure there is no race conditions / dependencies between these logical units
For instance, in Redux and Elm or Cycle.js you often see people trying to issue "several actions" in a row
that's not permitted
One action needs to complete, before the next one can proceed.
Edward Mulraney
@edmulraney
Jun 24 2016 17:36
how come?
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:36
Because that's the semantics of action
an action is not just a function
Edward Mulraney
@edmulraney
Jun 24 2016 17:36
ah -yes, they must be in sequence
serial
that's premitted?
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:37
You could implement some concurrency model, as long as the units of work do not overlap
serial is permitted, in particular that's a good use of nap()
Edward Mulraney
@edmulraney
Jun 24 2016 17:37
nap is for a single action?
its often that you want to execute a sequence
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:38
yes, there is logically only one "next action" in a given state
a sequence would then have to be implemented with the corresponding code in nap
because after the first action, you land in nap() again, and so forth.
Edward Mulraney
@edmulraney
Jun 24 2016 17:38
e.g. three actions (add1, subtact2, divide3)
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:39
Yes, exactly, nap will have to keep track of what's next
Edward Mulraney
@edmulraney
Jun 24 2016 17:39
but we dont want to tie nap(subtract2) onto add1, otherwise we can never use add1 without subtracting 2
nap can take multiple actions?
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:39
nap computes what's the next action
it knows about all actions, or it could be passed an action
Edward Mulraney
@edmulraney
Jun 24 2016 17:40
how could we execute the above example sequence (add, substract, divide)
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:40
It works a bit like Sagas, but nap does not keep state
Edward Mulraney
@edmulraney
Jun 24 2016 17:40
we want to reuse the actions to make two sequences
1: sequence(add, sub, div)
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:40
nap(model) => { switch(nextAction) { case: add ... }
Edward Mulraney
@edmulraney
Jun 24 2016 17:40
2: sequence(div, add, sub)
ah i see
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:41
nap is a function of the model that results in invoking one action
Note that since SAM enables API calls within actions or the model, you don't use nap as often as Elm, Redux or Cycle
Edward Mulraney
@edmulraney
Jun 24 2016 17:42
it seems we still cant define one action that would initiate a sequence of existing actions
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:44
You can also create composite actions when it makes sense, as you suggested earlier using the present parameter
add(data, function(data) { subtract(data, divide) ; } ) ;
Of course, no mutation on the model has occurred until the whole sequence is executed
Edward Mulraney
@edmulraney
Jun 24 2016 17:45
would each function not be mutating the model as it goes along?
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:45
That's handy to do API joins
It's your choice
the model is mutating when you call present, here you are composing function, the model has not changed
If the invocation of the second actions depends on the model mutation (via nap) then you have no choice than taking a nap
but you are in control, both models are supported
The problem with Redux or Angular for instance is that there is no nap and no hooks to implement API calls
Good luck with that
SAM is very prescriptive here because that's part of the programming model
wiring is not part of the programming model
Edward Mulraney
@edmulraney
Jun 24 2016 17:48
the present parameter could present multiple intent types, which are all processed at once, in sequence?
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:49
I would prefer the model deciding on the unit of work
I would rather keep one unit-of-work / dataset, rather than an array
Edward Mulraney
@edmulraney
Jun 24 2016 17:49
so create a new type altogether? type: SubAddDiv, payload {}
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:50
Maybe I am spitting hair, since they are kind of equivalent
as you just pointed out
I think it's better to keep it at two levels:
  • functional composition (no mutation)
  • unit-of-work + nap (mutation)
Otherwise you start defining a language for sequence, why pass logic to the model too? I think it's better handled with unit-of-work + nap
Edward Mulraney
@edmulraney
Jun 24 2016 17:52
agreed, not to pass logic
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:52
I am kind of specialist of orchestration languages (http://chorus.js) and what you call a sequence is in fact an orchestration
so very quickly you'll need more than just sequence
unit-of-work + nap works in all cases, the functional composition is just an optimization, I don't think it is wise to introduce more optimizations.
That's really the message I want to convey "semantics matter", you can see how easy it is to go down the slope to come up with your own.
Now, I am not saying that you can never introduce optimizations yourself, for your app, but at the pattern level, that's a big no.
I just saw that on linked in:
blob
I believe that's deeply and thoroughly flawed
Jean-Jacques Dubray
@jdubray
Jun 24 2016 17:58
semantics (blueprint) matter a lot, if you proceed with your own, you'll limit your ability to scale. You have to have the intellect of Leslie Lamport to come with Semantics.
I often take the example that from 1999 to 2001 I worked on a standard to define B2B contracts/protocols. The group was fantastic with people from Sun, CommerceOne, ... lots of prior knowledge from EDI.
In 2001 I was appointed chief-architect of the XML-STAR standard (Standard for Automotive Retail).
The first B2B protocol we had to design, the first one, not even the 10th or the 50th, could not be supported by the semantics we had created. We had not accounted for a contract where you could have many requests before you get a response.
That makes you humble, you work for GM, Ford, ... and you tell them we just spent the last two years building this B2B contract standard, and it fails on the first try.
When your semantics fail, then you find work arounds, that's when things get ugly.
You have to think deeply about your blueprint and consciously create optimizations, but if you start with the optimizations (or too high level, say like FRP), you'll end up creating a lot of work arounds.
Jean-Jacques Dubray
@jdubray
Jun 24 2016 18:04
That's why I am a bit disappointed with people from React, Angular, Cycle, ... they don't want to discuss their semantics at all.
Actually, Dan just posted this:
This message was deleted
Jean-Jacques Dubray
@jdubray
Jun 24 2016 18:10
That being said, I wish he (and the React team) would be a lot more careful about their semantics because once you use them, there is no turning back (aka refactoring)
devin ivy
@devinivy
Jun 24 2016 18:11
when you say semantics in this context can you give a specific example?
like in react creating a component by extending Component versus writing functional components? is that on the right track for what you mean?
Jean-Jacques Dubray
@jdubray
Jun 24 2016 18:16
IMHO, you need to answer the following question when you code:
  • what is an action? how do they relate to events?
  • how/when does application state mutation occur?
  • where are the hooks for API calls?
Fred Daoud
@foxdonut
Jun 24 2016 18:27
@jdubray @edmulraney @devinivy interesting conversation about components each having their own state/display/view etc. I agree with you, I'm glad to hear that you think this might be a good idea, because that is what I am trying to achieve. Each component can have its own state, display, view, nextUpdate (nap), receiveUpdate (model.present) function. For example: https://github.com/foxdonut/meiosis-examples/tree/todomvc-reorg/examples/todomvc/common/todoEdit
Encapsulating all the code that is relevant to a component is nice. And you still get the single state tree and single direction of data flow.
And if something is relevant to several components, you can still have that in a higher-level component.
devin ivy
@devinivy
Jun 24 2016 18:30
that last piece is crucial. the many-to-many relationship between "actions" and "reducers" is important and often lost when appealing to "modules" or "ducks" as they're called in redux-land (a bundle of actions and a single reducer).
similarly, the many-to-many relationship between views and branches of state.
saying "this branch of state is used by this view via these actions" becomes a roundabout way to implement mvc
Jean-Jacques Dubray
@jdubray
Jun 24 2016 18:37

I'm glad to hear that you think this might be a good idea,

actually, I am not so sure this is a good idea

I talked this week with the CTO of a startup who spent the last couple of years building an Angular app following that model and his advice is to never couple your business logic to the framework
I believe SAM really helps keeping the two separate
devin ivy
@devinivy
Jun 24 2016 18:38
i mean, angular is an extreme case
Jean-Jacques Dubray
@jdubray
Jun 24 2016 18:39
I would argue that components like this one (React) is an anti-pattern:
http://browniefed.com/blog/react-art-zooming-and-dragging/
devin ivy
@devinivy
Jun 24 2016 18:39
if you wrote angular services you might be screwed even porting those elsewhere
Jean-Jacques Dubray
@jdubray
Jun 24 2016 18:39
@devinivy the problem is that frameworks will keep changing, there will be Angular3 and 4 and 5
devin ivy
@devinivy
Jun 24 2016 18:39
right, and an angular service is not a general-purpose way to write a service
Jean-Jacques Dubray
@jdubray
Jun 24 2016 18:40
:-)
blob
I showed him that picture and (in principle) he liked it
Fred Daoud
@foxdonut
Jun 24 2016 18:51
As has been said before the idea is to facilitate the approach that makes sense. Whether a component has its own pieces of code, or sometimes it makes more sense to have the code in a single root place, both are possible.
Of course you don't want your business logic buried in a component. But on the other hand, sometimes some code only makes sense within a component. That is, if you remove the component, you would remove that code too. In those cases, it's better to have that encapsulated instead of hunting it down in a big root function.
Jean-Jacques Dubray
@jdubray
Jun 24 2016 20:43
I am not saying do not put any code in the components, however, the only code you should put is component oriented, not model/application state, not action, not nap(), not even state, unless it is a true (control) state of the component.
Fred Daoud
@foxdonut
Jun 24 2016 20:46
agree
why not nap() though? consider a form input field, with nap() = "after save, clear the input field"
Jean-Jacques Dubray
@jdubray
Jun 24 2016 21:59
nope ... the programming model says that this kind of behavior is implemented via V = f(M), the model says the input field is empty.
nap() is truly for triggering actions that will mutate the application state
It is very important to be disciplined about the semantics, I cannot emphasize that enough
So far, the only DOM manipulation I had to do in nap() is "focus".
There is no declarative way to do that
But thinking of it, I should be able to do it the same way I did it for draw rectangle with a state representation that is a function.
Jean-Jacques Dubray
@jdubray
Jun 24 2016 22:05
So I had a "search field", after each key pressed I update the list of records (via V = f(M))
You need to focus the field with the cursor at the end of the string. This can be achieved like this:
var _nextAction = (model: any) => {

        if (model.focus) {
            console.log('refocusing query field '+ model.focus) ;
            setTimeout(function(){
                var el: any = document.getElementById(model.focus) ;
                if (el) {
                    el.focus();
                    var val = el.value; //store the value of the element
                    el.value = ''; //clear the value of the element
                    el.value = val; //set that value back.  
                }
            });
        }

    } ;
Clearly I am breaking the semantics, since that particular action has no application state impact
it looks like this could be achieved by passing a function in the state representation that will be handled in the view display:
     stateRepresentation = { 
            focus: (el: any) => 
                   setTimeout(function() {
                if (el) {
                    el.focus();
                    var val = el.value; //store the value of the element
                    el.value = ''; //clear the value of the element
                    el.value = val; //set that value back.  
                }
            }), 
       rows: [{...},...]
   }
Jean-Jacques Dubray
@jdubray
Jun 24 2016 22:12
You have to let go "object orientation", the kind of encapsulation that OOP brings is unhealthy. OO is an anti-pattern.