Closed vivekimsit closed 9 years ago
We all thought about this, finally one is speaking it out ;)
I think there are a few problems to solve. Everyone has opinions about how thinks has to be solved so these components should be flexible enough.
This is normally done with configuration. But if you do this, the components tend to get quite complex and large.
On the other hand, with mithril things got quite simple to implement. So in most cases it is easier to reimplement your component specific to your usecase.
Other questions that arise:
This shouldn't keep us away from doing it. Maybe open-source-evolution will figure this out.
Yes,
From this project we will learn:
Would like to listen from others too :)
Thanks!
just found https://github.com/mithril-ui
Seems monolithic and outdated. Also it's bound bootstrap what I personally don't like.
There is also https://github.com/ng-vu/mithril-bootstrap from the same person (@ng-vu)
Satyam and I wrote one of the earliest component repos https://github.com/eddyystop/mithril-components. We thought then a standard set of Mithril components was important to acceptance, and I still think so now.
The problem has always been the lack of a canonical component design that turtles all the way down, and allows some components to expose some of their state to others. You'd want components from different authors to play nice with one another.
Like other people, I've rolled my own components, including some sophisticated ones, yet they can't be shared.
Hi guys,
I created mithril-bootstrap just for experience how to structure projects and components in Mithril. For now, I agree that it's easier to reimplement components for our specific usecases or wrap other libraries in Mithril-style than force everyone to follow a single style.
JavaScript is evolving rapidly. Yesterday I used RequireJs, today Browserify and tomorrow maybe ES6 Modules. It's up to people to organize their projects and requirements.
Ya, it would not be that trivial but I think its a good project to start with. After all it can show the real power of mithril.
WDYT?
@ng-vu Totally agree.
Thats why I also think the web-components movement is a dead-end. Easy-to-implement custom tailored components are the way to go. That's why mithril rocks ;).
So conclusion of this issue would maybe to create a list of possible patterns for mithril components where anyone can get inspired and inspire others.
Don't quite know how to achieve this. Maybe a wiki, but this tends to outdate.
Any ideas?
Hello,
I believe a component store would be very nice but I also understand that a reusable component is very complexe to implement because of the required flexibility.
What about a component snippet store ? You would be able to share your components without to search for flexibility. Others can reuse and adapt them to their own needs and maybe can share their new version with different features.
For Boostrap related stuff, there is http://bootsnipp.com/ which offers exactly this kind of stuff. You find code snippets which are ready to use ; but most of the time you adapt them to your own needs.
Damien
Le 16/01/2015 11:50, Stephan Hoyer a écrit :
@ng-vu https://github.com/ng-vu Totally agree.
Thats why I also think the web-components movement is a dead-end. Easy-to-implement custom tailored components are the way to go. That's why mithril rocks ;).
So conclusion of this issue would maybe to create a list of possible patterns for mithril components where anyone can get inspired and inspire others.
Don't quite know how to achieve this. Maybe a wiki, but this tends to outdate.
Any ideas?
— Reply to this email directly or view it on GitHub https://github.com/lhorie/mithril.js/issues/413#issuecomment-70237406.
@tracim, I find the idea of a snippet store interesting. In addition to what you mention, it sidesteps the issue of what CSS to decorate the tags with e.g. custom classes (m-dropdown-component) vs Bootstrap classes.
:+1:
I think this is a great idea. Too many people want stuff that just plug and plays, but the truth is you can't write terse and elegant plugins that accounts for everybody's intended usage and caters for all their desired configuration with totally plug-and-play code. People have tried to do this in the past and ended up with the huge bloated nightmares that are jQuery UI and Angular.
If anything, Mithril's philosophy is that functional code should be kept short and sweet and obvious, that way users can learn a little by looking into it and customise it to fit their situation.
Plus, this encourages development and configuration over dumb copy+pasting, which has got to be good for the community.
:+1:
Snippet store seems interesting idea. That will be a kind of cookbook.
A Mithril Cookbook would be a great resource, given the way people seem to recommend developing with Mithril (solving your own problems effectively and not writing a mini-framework about it). Having several recipes for solving a focused task can be useful when you're learning. Depending on your coding approach (functional, prototypal, class-based), there might be several idiomatic implementations for the same recipe. One concrete example of how this could work is ActiveState's language-specific cookbook recipes; several of the subsites have even been turned into O'Reilly books. Collecting recipes for solving common tasks would be a good start.
I agree that Cookbook or a collection of snippets would be a perfect way to learn Mithril and to help people make their own custom components. But Mithril needs to gain popularity and I think if a newbie will see just a list of recipes, and he won't be able to npm-install then to quickly test - he will be disappointed and will go back to React with their react-components repo. I personally find Mithril much more solid and useful than React. But I still have to use React because of its Material Design components, and because I can't assure my colleagues to use Mithril since nobody ever heard of it. So recipes are important to learn Mithril. But pluggable components are important to start quickly use Mithril and to help it become popular.
@zserge are you referring to https://github.com/callemall/material-ui ?
@eddyystop Yes, subjectively it seems to be the most usable set of Material components to write mobile HTML5 apps (I've also checked Bootstrap Material, Angular Material and Polymer Project).
Totally agree with @zserge
In fact to develop a strong community we need a strong POCs
cheers!
I would think callemall/material-ui custom less CSS would concern some people, as opposed to, say, Bootstrap 3. Any information on this?
I guess one idea is to keep someone's material UI less and redo the JS in Mithril.
@eddyystop You mean they're using different element classes than Bootstrap? I don't see a problem here, since these two are very different:
And I totally agree that "borrowing" LESS styles from the material-ui would simplify things a lot. Or maybe from the Polymer, which also looks nice on mobile.
@zserge "Polymer is based on a set of future technologies, including Shadow DOM, Custom Elements and Model Driven Views." So its further removed from the Mithril philosophy than Material-UI or Bootstrap.
The Material-UI and Bootstrap CSS can force the HTML to be structured differently. So you'd need a separate library for each, though they would be similar.
@eddyystop Yes, I agree that Polymer is very different from Mithril and not suitable for porting. I copy-pasted some CSS blocks from there in the past to mimic material UI, so it's possible, but not convenient at all.
React's approach is much nicer, of course.
Also I don't think Bootstrap for Mithril and Material UI for Mithril would have any similar code at all.
Anyway, it looks like we agreed that Bootstrap and Material should be implemented for Mithril. Other ideas? If we make a list of components - we can decide how flexible they should be, probably some requirements and implementation details etc and actually we could start working on them.
@zserge, I replied in the Mithril google group ( https://groups.google.com/forum/#!topic/mithriljs/4C4xwYtanjY ) as that may be a more appropriate venue.
I'm comfortable with the info I've picked up in the Mithril google group. Is anyone at least semi-serious in developing a UI library?
:+1: of course I am the one.
Yes
My thoughts:
My suggestion is that we contribute to https://github.com/philtoms/mithril-starter-kit. Its the starter library for mithril.elements and its based on Bootstrap. Its current components illustrate how to use mithril.elements.
One approach to contributions would be to take the Bootstrap docs
I'll be rewriting components I have for dropdowns and for nav bars.
Although I'm not a fan of the bootstrap look, I do think it's the appropriate choice if we want to popularize mithril.
Bootstrap makes extensive use of jQuery. I wonder if we might start out by formalizing 'standard' javascript snippets to replace jQuery equivalents, specifically in regards to functional programming and object manipulation. I'm not sure how to treat DOM manipulation vs. virtual DOM manipulation. That might require evaluation on a case-by-case basis. (I'm assuming we want mithril components to function without dependencies)
We might also want to start a 'best practices' guide.
I don't want us to get too bogged down, we should just start hacking now. But having a single source of truth early on might save a lot of refactoring.
I've converted various Bootstrap "javascript components" that use jQuery into mithril plus pure javascript. Its usually straightforward and the resulting mithril code is much easier to understand.
You just have to know what an action would cause and implement the effect in Mithril. Consider a dropdown. Bootstrap manipulates the DOM with jQuery to show or not show the dropdown items. With Mithril you check view-model state to see if the dropdown is open and render the items or not. Much simpler.
I implemented the complex Affix component ( http://getbootstrap.com/javascript/#affix ). Its the sidebar menu floating on the right of the page. You'll see it "land" when you scroll to the top of the page. The key was figuring out what Bootstrap's jQuery addon was doing to the DOM.
The take-aways are that its not hard to implement Bootstrap "javascript components" and that you shouldn't focus on the jQuery.
Most of the time plugin behaviour consists of querying values and changing 'nearby' DOM attributes, which is trivial with Mithril. It's been mentioned before, but things get a bit confusing if you've been using modules where DOM hierarchy matches model hierarchy (why wouldn't it?) and suddenly you discover a situation where that isn't the case (tooltips – crap!). I recently came up with this pattern for defining a view in one place and outputting it in another, which might come in handy for the many components that require some form of overlay. http://jsfiddle.net/barney/Laxn4jem/
Regards, Barney Carroll
barney.carroll@gmail.com +44 7429 177278
barneycarroll.com
On 23 January 2015 at 17:19, Eddyystop notifications@github.com wrote:
I've converted various Bootstrap components that use jQuery into mithril plus pure javascript. Its usually straightforward and the resulting mithril code is much easier to understand.
You just have to know what an action would cause and implement the effect in Mithril. Consider a dropdown. Bootstrap manipulates the DOM with jQuery to show or not show the dropdown items. With Mithril you check view-model state to see if the dropdown is open and render the items or not. Much simpler.
I implemented the complex Affix component ( http://getbootstrap.com/javascript/#affix ). Its the sidebar menu floating on the right of the page. You'll see it "land" when you scroll to the top of the page. The work came down to figuring out what Bootstrap's jQuery addon was doing to the DOM.
The take-away is that its not hard to implement Bootstrap "javascript components".
— Reply to this email directly or view it on GitHub https://github.com/lhorie/mithril.js/issues/413#issuecomment-71228642.
It might be useful for anyone attempting to convert bootstrap-jQuery to bootstrap-mithril to take a look at https://github.com/react-bootstrap/react-bootstrap, especially for clues when to redraw and in rare cases when you need direct DOM manipulation.
I seem to remember issues with click responses on iOS and the need to get this directly from the DOM.
I am also not a big fan of bootstrap, I like polymer more and after that the material design implementation by react is awesome.
Also, one thing about polymer is that it doesn't depend on any other third party library
I think Bootstrap fulfils a different role (as far as we're concerned) in that it provides standard functionality and appearance for various standard UI components that native HTML doesn't do it off the box. Implementation is kind of besides the point (I'm looking at using a Stylus fork, for instance, for the sake of isomorphic CSS logic).
When I'm discussing how to represent a piece of functionality with a UX specialist, it's trivial to be able to suggest a composition of Bootstrap components that provide the necessary low-level functionality. Whether I'm going to use jQuery or SASS or the baked-in Bootstrap theme is besides the point — what matters is that we can easily communicate in shorthand about standard user interaction mechanisms in terms of end-user functionality without bike-shedding about implementation details.
Polymer on the other hand says everything is possible, but has reduced value in that the specifics get lost.
To put it another way: people who want to reinvent the wheel with a standardised low-level API for defining the roundness of the wheel will be interested in Polymer. People who assume a generic roundness out of the box and just want a variety of different wheels (with some tweaking down the line) will want a Bootstrap. You could implement Bootstrap components via Polymer, and implement the Polymer runtime in Mithril for all I care, but Bootstrap has (really) useful specifics.
Which do we want to work on? I think the problem here is one of PR — we want to solve other people's problems but we're not sure who those people are.
On Saturday, 24 January 2015, vivek poddar notifications@github.com wrote:
I am also not a big fan of bootstrap, I like polymer more and after that the material design implementation by react is awesome.
Also, one thing about polymer is that it doesn't depend on any other third party library
— Reply to this email directly or view it on GitHub https://github.com/lhorie/mithril.js/issues/413#issuecomment-71326710.
Regards, Barney Carroll
barney.carroll@gmail.com +44 7429 177278
barneycarroll.com
If you're a programmer with in-depth experience in another framework (angular, ember, backbone), there is likely a bootstrap->yourFavoriteFramework conversion on github that should speed you along in creating mithril components. I'm sure that's true of polymer and maybe of material design, but I suspect the bootstrap libraries are better tested across browsers.
I vote for bootstrap.
@eddyystop I see a lot of people tend to agree with mithril.elements approach. I feel really dumb, but what is the benefit of using mithril.elements? I always seen mithril components as just a view function. It may have a predefined private controller, it may export some attributes, getters, setters, it may receive some arguments to configure its behavior. Something like this (I'm far from being a good JS developer, sorry): http://jsfiddle.net/96356ngx/
But with mithril.elements approach I see a few disadvantages:
Could you please clarify what is the reason against using pure JavaScript + Mithril for components?
@zserge, the intended benefit of mithril.elements is to extend the DOM through custom elements. It does this by aligning standard mithril components with the prevailing DOM life-cycle. This might not seem like a big deal (and you can view the code to see that it isn't from an implementation perspective) but it allows you to compose complicated element types and use them intrinsically. Also, the resulting 'elements' play very well with standard mithil views and allows 3rd party library elements to be composed idiomatically. Thats the point of mithril.elements really.
The another library issue depends on whether you are a one-core supporter or whether you prefer small component based solutions I guess. I can't really see it as a technical disadvantage though, especially in the light of tooling like Browserify and Webpack (Mithril Starter Kit is geared to deliver all modules through Webpack).
By not type safe I assume you mean tag names are strings rather than object instances? There is a discussion going on about this here but briefly, I don't see why string based element tag registration is any less typesafe / autocomplete friendly than mithril's current string based tag identification scheme.
I wont try to argue your last point, it seems subjective, and anyway, I think most of us already enthralled by mithril will welcome Leo's latest development ideas towards element / tag support. I'd like to think that mithril.elements as played its part in helping to expand the scope of this fantastic framework.
@zserge, @lhorie is looking into moving something similar to mithril.elements into mithril core.
Let me look at this from a code-on-the-page perspective. mithril.elements showed that sub-component controllers can be automatically instantiated in the component view for many of the sub-components we are likely to use. We no longer need the boilerplate in component controllers to do this. This saves a fair amount of LOC with associated issues and, let's face it, it looks good.
Beyond that, there are advantages to any standard way of doing things. (And disadvantages.) I think one of the main reasons the different initial Mithril UI repos went dark is because each had its own 'standard'. mithril.elements is a potential standard that does several things rather well.
Your items 1&3 are handled assuming the new m.tags[] lands. I agree with @philtoms on # 2, mithril is already string based for tags.
I use a pattern I call reveal-view-pattern for some of my components. The component is pretty much a controller that returns a view function instead of a scope. The view function then can be customised elements-wise.
Here is my inline edit component which uses this pattern.
@StephanHoyer This totally matches the way I've seen the components for mithril! This looks more pure to me, it requires no changes to Mithril and it clearly separates DOM nodes (quoted strings) from components (functions). You can also easily deal with namespaces here, if two libraries provide, say, modals, you can assign them to two different variables and use both, while with strings you can only hope that another developer didn't take a cool component name "modal".
Yes, that's the point. Me personally, I find the mithril syntax pretty ugly but it's better than adding another template language or creating functions for every span, div, table and so one. It's a pretty solid solution but you don't want to piggy-back on this, if you don't have to. That's why I use functions for this. They are more flexible and packaging and integration are far simpler.
@StephanHoyer :+1:
For those here who are not participating in the Google Group for Mithril, just to make you aware of my proposal for creating components in Mithril, which as of version 0.1.29 is nearly all the way there:
https://groups.google.com/forum/#!topic/mithriljs/wZgudHBk210
and the example Todo mini-app:
@lawrence-dol This seems to follow the current vision of components (http://lhorie.github.io/mithril/components.html), and matches my vision of them. So I still wonder what's wrong with this approach and why something new should be added to Mithril? How is m('filter'') better than filter.view() or just filter() in some cases?
@lawrence-dol looks interesting, but your variable names are awful to read... took me a time to get the whole thing.
Your attempt pretty much aligned with my attempt. The only difference is that I return the view function directly and avoid the use of new
and constructor
-stuff but use only functions.
But I still don't get, in which way mithril has to be improved to make it component ready?
@StephanHoyer @lawrence-dol So far I've seen three ways to implement components. I've combined them all in one place in this jsfiddle: http://jsfiddle.net/hnp4vdxv/
Please, have a look.
The first way is to make a view-function. That's my favourite one. It's very easy to use (code is very short and readable), but it's not Mithril-way, since there is no separate controller, it's hidden inside a constructor function. Still, it resembles me the "partially applied modules" that Leo mentioned in his blog: http://lhorie.github.io/mithril-blog/module-partial-application.html
Resulted components can accept options during their creation, can expose public API, and can access child views or attributes if needed (like c.modal({className: '.my-modal'}, m('.content', m('p', 'Some Text')))
, where c.modal is a component view function).
The second way is a typical Mithril module, this was described by Leo here: http://lhorie.github.io/mithril-blog/organizing-components.html It's also nice, it needs a bit more code to use components, but it's pure Mithril way (controller constructors and view functions with controller arguments). As in the first case, resulted components can accept options in their controller constructores, controllers may have some public API, views can take custom attributes etc.
The third way is new Mithril core via m.tags. Components are created much in the same manner as in the second approach. Using components seems to be easy (as much as in the first approach), but I don't see a way to use components API. Am I wrong here?
So far I pick the first way, since it's important to let people use components easily, and I don't see much disadvantages of the first way. The second way looks a bit bloated, but still is viable. The third way is a big surprise to me, since it seems to be the least flexible. So why is there so much discussion around it and what's wrong with the first and the second ways?
I always saw controllers as optional. Only if you want to put a route on it they become mandatory. So I don't see why the first attempt goes against any mithril rules. I find it by far the most pretty one.
@zserge and @StephanHoyer your opinions would be worthwhile in a rather big discussion happening about components in the Mithril Google Group.
For example: https://groups.google.com/forum/#!topic/mithriljs/wZgudHBk210 https://groups.google.com/forum/#!topic/mithriljs/f-asji8qoFM
Ok, then maybe let's close this issue here.
The m.tags approach solves one important problem that the other two do not: it lets the framework manage component lifecycle. Say you have something like this:
function myView(ctrl) {
return ctrl.someData.map(function(item) {
return m("MyComponent", item.name)
})
}
Say MyComponent has to clean up some web socket subscriptions when it unmounts. With the first two approaches, if you delete an item, you have to manually call onunload on the respective component, (plus sync up the list of components), which is a pain.
The trade-off that comes w/ m.tags, as @zserge mentioned, is that w/ m.tags you're no longer able to consume a component's controller API from a parent controller.
Now, the question of whether a controller prototypal API should be consumable from another controller in the first place is a much bigger conversation.
In Lawrence's example, you'll see that TodoList depends on SimpleTextFilter (i.e. the SimpleTextFilter instance is injected into TodoList as an argument and is expected to have a .matches
public method). But if instead you needed a AllFieldsSearchFilter, you'd be duplicating the template for SimpleTextFilter. This may be fine for a single input tag, but starts looking like a code smell if the UI control has more complex markup (e.g. an autocompleter).
I talked about that topic here ( http://lhorie.github.io/mithril-blog/an-exercise-in-awesomeness.html ). The gist is that while tying logic to controllers is not disallowed and it accomplishes the task at hand, it can cause maintenance problems down the road.
Changing the signature of a module from {controller: () -> {}, view: () -> {}}
to () -> {view: () -> {}}
doesn't fundamentally change anything. Getting rid of the word "controller" isn't enough to make controller-less components. All that happened is that now the constructor takes the role of the controller. You can still stuff logic there, and you can still run into the same maintenance problems.
The alternative is to move filtering logic to the model layer. This is essentially what is advocated w/ architectures like Flux and MVI (which, imho, are all classic MVC w/ different names). These architectures use the observer pattern to chain reactive dependencies. In my own code, I tend to simply have a two step process: various action handler methods to respond to specific actions (e.g. remove item from list), and a update everything method that gets called at the end of action handlers (this update-everything method may or may not be the same as the model object initializer, depending on whether I want to reload from the server or not). In the filtering case, the update-everything method would update a filteredItems
property, and that is the property that would populate the list from the beginning. In this way, the list component is completely agnostic of whether filtering occurs or not.
The role of a component (in the m.tags sense), as I see it, is to encapsulate state that you don't care about outside of the component's scope (e.g. whether the suggestion list in an autocompleter is currently visible). State that pertain to the application should still follow the MVC flow if you want to be able to manage it effectively.
Thanks for clarification.
Can't we just grab the base element of the component and use the config -> context.onunload
here?
@StephanHoyer it gets ugly in some cases. As I mentioned, one consequence of having a component that exposes methods for controller consumption is that you then need to keep track on component instances in your own code. So, again, with the list example, removing an item from the list requires that you also remove the corresponding component from your list of components. If you have to sort the list, you're essentially going to be forced to re-implement the keys algorithm in app space.
Also I'm not super convinced that OOP-style cross-controller communication scales. Past a certain depth of components, you're likely going to be running into silly things like parent.parent.parent.child.child.child.doSomething()
Hi,
What about creating a repo which contains a set of reusable UI components? something like Angular-UI or Khan Acacdemy
I am ready to contribute.
Cheers!