The idea of smart and dumb components in Elm - elm

I like React's/Redux' concept of smart and dumb components, where a dumb component does not handle its own state (Dump component does not know anything about the outside world, all it does is triggering an event and displaying value according to its input). This is trivial because all state in handled in one place (main reducer).
In Elm, each component has its own 'update' function (similar to Redux' reducer), so it does not seem trivial to use the same (dumb & smart components pattern).
Is using smart & dump components a good practice in Elm? If so, will I have components without 'update' method? I wonder how will I pass data (props) to my component and how will I trigger events to the parent component.
I will love to hear your thoughts.

The Elm equivalent of a "dumb component" (a.k.a. Presentational, Pure, Skinny component) is simply a function that produces Html:
view : ... -> Html
The elm-html library is written in this style, e.g.,
button : List Attribute -> List Html -> Html
You set the "props" by providing attributes when you call the function. In particular, you register events by supplying handlers in List Attribute:
button
[ onClick addr ClickAction ] -- event handler
[ text "Click me" ] -- child "components"
You'll see this pattern also in other libraries, although the exact types may be different from List Attribute and List Html.

Another Smart/Dumb distinction you can make is between components that return Effects and those that don't. But to answer your question...
Nothing stops you defining actions in a child
type Action
= Submit
| Click
and in the Parent view having
Child.view (Signal.forwardTo address ChildAction) props
(We pass props because there is no model data as such to pass)
but then handling all the actions in the Parent's update:
case action of
ChildAction act ->
case act of
Child.Submit ->
...
Child.Click ->
...
This would be essential anyway if the impact of an Action in Child was to change the state in Parent or some other child of Parent.

Related

Vuejs: shared states between components

I would like to know the best practice for implementing shared states between components in Vuejs.
Imagine situation A: you have a web app that shows a modal. The modal has the boolean state show. This state should change if the modal OK-button is clicked, but also if any part of the background is clicked, and perhaps even on some server pushed state change. Thus the modal should be able to change the state as should the parent app.
Situation B: you have a web app that shows input fields inside different components that share a common data value. If the user changes value through the field in one component, it should also update in the other. Again both should even update on a server push event.
Questions:
I am right that the correct way to go about this would be to use vuex and make the shared state a store field that is observed by and changed through emitted actions by all components / parents that need to modify that value?
Does that not introduce this kind of dangerous (since hard to handle) magic reactivity that we know from Meteor?
How to best document the flow, what depends on what?
A: For a modal component, I'd say that show should be a prop. So the parent component can control the modal whatever it wants. In this case there is no shared state at all.
The modal itself doesn't need to know anything about the server. If the prop show is true, just display the modal and vice versa.
I think the mask layer is a part of the modal, so when the mask is clicked, the modal emits an event. The parent component receives the event and can decide to hide the modal or not to.
Vue has an official modal example here (thanks #craig_h for mentioning): https://v2.vuejs.org/v2/examples/modal.html
B: Just bind the vuex state to the inputs. Nothing wrong.
Note that not all the components need to access the vuex store directly. For some pure UI components, just use props. So the parent components have the right to control them and increase flexibility.
I recommend you to read these docs:
https://facebook.github.io/react/docs/lifting-state-up.html
https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.j7ry4a3as
http://redux.js.org/docs/basics/UsageWithReact.html
Yes these are React / Redux docs. Since Vue is relatively young, react community has more documentation / articles. But both Vue and React are component-based libraries. The idea of how you design a component is basically the same.
You can also take a look at this vuex example: https://github.com/vuejs/vuex/tree/dev/examples/chat
This is a very simple example but it does use all the things I mentioned above. Emitting an event, some pure UI components...

Vue.js 2.0 - creating reusable components

I am trying to create fully reusable component using Vue.js 2 and single file components, and right now my approach seems to be impossible to realize.
The goal is to create component for creating forms for a complex, nested JSON structure. This structure is supposed to be edited and then sent to the server. The component itself displays a header and submit button but the fields along with their placing is entirely the responsibility of the user of my component. (front-end engineer)
The MyForm component (implementation is not relevant here) is passed the JSON data and url to post them to.
The form is supposed to be reusable by many other users and the contents of the form itself is supposed to be not relevant. It may have a mix of html/inputs/custom components as children.
Let's imagine a simple scenario without data nesting with the following data:
var mymodel={ name : "My name", surname : "My surname" }
And a form i would like to create using my component:
<MyForm :model="mymodel" :url="http://localhost/post">
<div>
<MyTextInput v-model="model.name" label="Name"/>
<MyPanel>
<MyTextInput v-model="model.surname" label="Surname"/>
</MyPanel>
</div>
</MyForm>
Therefore:
MyForm gets passed a model to submit, stores it in data
MyTextInput is a custom component for displaying input with label
Second MyTextInput is the same component but created in another component contained called 'MyPanel' since this field needs to be placed differently.
As we can see there are many problems with passing variables and composition itself:
Composition:
If i put a <slot></slot> in the tempplate of MyForm for displaying the fields it would be compiled in parent scope, therefore all children (including MyTextField) would not have access to the "model"
If i try to use <MyForm inline-template> i cannot automatically display the form header and footer since all content is being replaced. Additionally when using single file components the compiler will look for all components inside the inline-template which means that i would have to import MyTextInput and MyPanel into MyForm which is not practical. I do not know in advance all components that will never end up in my form!
Passing variables:
If i use the variables directly from "model" (in first TextInput) i receive warning that i am modifying a variable from parent and it will be overwritten on next render (but in this case it will not be overwritten since i am INTENTIONALLY modifying the parent)
I cannot pass the model into second MyTextInput without passing it to MyPanel first. Actually i would have to pass it into EVERY custom component in between. And i do not know in advance how many custom components will there be. Which means that i would have to modify the code of every component that would ever be put into MyForm and require users to pass the data for each custom component they include.
If i would try to properly inform the parent about changes i would need to add v-on: event to every textinput and every custom component in between in order for the event to reach MyForm.
As i have said the component was supposed to be simple and easilly reusable. Requiring users of this component to modify code of every child they put into it and requiring them to add v-on: to every component inside does not seem practical.
Is my idea solvable using Vue.js 2.0 ? I have designed the same component before for AngularJS (1.5) and it was working fine and did not require to add modifications to each child of the form.
I've been using a ui framework based on vue 2.0 and you may get some ideas from its implementation. Based on its implementaion and my little experience with it, I think it's the person who uses your framework's responsibility to assemble the form-model. Also, for a form, we can always easily get all the data to be sent by using fields' value props without v-model's help.
The framework's doc on form element may also be helpful but it's currently only available in Chinese except for the code samples.
I suggest you to use Form Input Components using Custom Events to pass variables in your form.
Mutating a prop locally is now considered an anti-pattern, e.g.
declaring a prop a and then set this.a = someOtherValue in the
component. Due to the new rendering mechanism, whenever the parent
component re-renders, the child component's local changes will be
overwritten. In general, in 2.0 you should treat props as immutable.
Most use cases of mutating a prop can be replaced by either a data
property or a computed property.

Vue common component communicate with different parent

I have a requestion, how about vue.js's common component's best practice when communicating with different parent component.
for example, in my scenario, a basic modal component, trigger a 'close' method, but it has two different parent component
I find two solutions:
parent need pass an additional prop, and then baisc component just
trigger event which event's name is the prop value, so the listener
parent component attched on could be called
in basic modal just use this.$parent to visit parent component methods, or this.$parent.trigger('xxx'), and then parent knows what to do
But, both above I think not very good, the first may need pass an additional prop, this let others who write a third, a forth parent component use the basic component not very handy. And the second may be felt more hard coded.
So, is there is better solution in this case?
Use this.$dispatch('eventName', data) (for Vue 2.x, use this.$emit('eventName', data)), to trigger an event to any parent, grandparent and further up the chain (you can use this.$broadcast('eventName', data) to trigger events down the chain in Vue < 2.x).
If the parent has an event called 'eventName' then it will fire this event.
If you have multiple parents, you can give them each a different event and from the child fire this specific event via dispatch. You can also give each parent the same event and pass a data prop that specifies what the parent should do. Third option is to refer to the specific parent:
var parent = new Vue({ el: '#parent' })
// access child component instance
parent.$refs.eventName()
Each option has pros and cons. The best solution depends on the context. But I think that the best solution in general is option 1. Then you don't need an additional data parameter. Option 3 is not loosely coupled.
For more info: https://vuejs.org/guide/components.html

Mithril.js: Should two child components talk to each other through their parent's controller?

I'm a bit stuck looking for the right way to do the following. I have a parent component with two child components (see simplified code below). I would like to know the proper way for ChildA, when its button is pressed, to 'invoke' ChildB. They should communicate through the parent, but should they communicate through their controllers? In that case the parent has to pass its controller to the controllers of the children.
Parent = {
view: function () {
m.component(ChildA);
m.component(ChildB);
}
}
ChildA = {
view: function () {
m('button')
}
}
ChildB = {
view: function () {
}
}
This is really just a question of the plain javascript style you prefer. Think of communication between JS objects and how you would handle that.
Generally, Mithril devs choose between Parent/Child communication and Pub/Sub. For Parent/Children, the controller is commonly where devs place their logic. m.component accepts multiple parameters in which you can pass references (data/state/logic) to child components. See the docs. There's no need to pass Parent controllers to children.
However, I prefer to create a view-model which lives outside of any one component. It's where I keep view state (ie. form data) and view logic (ie. events, UI related callbacks, and shared state between components). This way, when I inevitably change/add components, I will not have to rework the controller logic in each component.
Leo Horie, the author of Mithril, wrote an article in which he explains communication between a Parent and One Child, but this can effortlessly be applied to multiple children.
Pub/Sub is a common JS idiom. The Mithril wiki lists a few community contributions that handle this. Go to the wiki, open the page titled "All Topics" and do a normal page search for "pub". You'll discover a few options there. Depending on the complexity of your app, your next move might be to search for a Pub/Sub library through google.
I guess when you press the button of ChildA, some model state will be updated? Then, if both childs share the same model, the redraw done by Mithril after each event will update ChildB automatically.
My suggestion is to pass the model to the child objects and let ChildA also be a controller for the button. Why not the parent? Parents should usually handle commands that apply to multiple child views (or itself), and a button click seems simple/coupled enough for ChildA to manage that itself. But it depends on the real complexity of the system, of course. Always the problem with a simple example, it does not describe reality. :)
Here's an example how I mean anyway: http://jsbin.com/sipahe/edit?js,output
(Sorry for the Coffeescript, but it's brief and conveys the meaning very well.)

Communicating with Knockout components

Is there a way to communicate from the parent viewmodel to a KnockoutJS component?
I have a component that contains a bootstrap modal dialog box, to search for customers and return a selected customer. At present, to make the dialog box appear, I pass an observable boolean from the viewmodel in the component's params attribute. To make the dialog appear I set this to true, which invokes the dialog box. I also pass a callback function in params to return the results.
Here is a fiddle demo which shows the concept: http://jsfiddle.net/Quango/5bxbsLt6/
Passing the observable boolean to invoke the dialog doesn't feel right, but it's the only working solution I have. The only other idea I had was to use ko-postbox to create a publish/subscribe function.
It feels like there should be a way to invoke actions, e.g. component.Show() ?
I think the answer here is that there isn't a better way. To communicate from a parent viewmodel to the component, pass an observable value, and then use that directly or subscribe to changes in the component.
I will put a suggestion on the Knockout github project to consider some form of interface.