-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Discussion about router #64
Comments
Maybe it is better to use blocks for nesting. Then render is called consistently for any type of hierarchy. class A
include Clearwater::Component
def initialize(&children)
@children = children
end
def render
puts 'render A'
div({id: 'A'}, @children.call)
end
end
class Layout
include Clearwater::Component
def render
div({id: 0}, [
A.new do
div({id: 1}, [
B.new
])
end
])
end
end |
This is a little surprising, but can you think of a case where it would make a difference in how I would write a particular component? |
I was trying out an idea where nested components needed to get information from a 'parent' higher up but passing down attributes was not an option. React has The block style solved my issue so I'll close this ticket. |
I'm not sure I understand. Do you mean like in your example above where you construct the I do something similar sometimes with a MasterDetail = Struct.new(:master, :detail) do
include Clearwater::Component
def render
div([
div({ style: Style.master }, master),
div({ style: Style.detail }, detail),
])
end
module Style
module_function
# style methods for above
end
end
class Layout
include Clearwater::Component
def render
MasterDetail.new(UserList.new(users), UserDetail.new(selected_user))
end
end |
I agree that some of this should be documented, btw. We're mixing function calls (the HTML tag methods) with objects whose values are delayed until the sanitization pass. And then there are |
Interesting, I like the style of MasterDetail. Looks similar to 'pure components' in React. I was toying with an idea of a declarative router similar to what they are doing in react-router v4. def render
Router.new do
div({ id: 'app' }, [
header({ class_name: 'main-header' }, [
h1('Hello, world!'),
]),
Match.new(pattern: '/about', component: About),
Match.new(pattern: '/articles', component: Articles),
Miss.new(component: Articles)
])
end
end but execution order of render becomes a problem in nested matches. For instance def render
div({ id: 'articles-container '}, [
input({ class_name: 'search-articles', onkeyup: method(:search) }),
ul({ id: 'articles-index' }, articles.map { |article|
ArticlesListItem.new(article)
}),
Match.new(pattern: '/:article_id', component: Article)
])
end And as you say, I haven't even begun to look at the effects of CachedRender :) |
I love some of the ideas behind RR4 and I wondered, too, if it was possible to do something like they did. :-) There were a few things that kept me from being able to do it successfully:
I wonder if we could make it work with another hypothetical mixin: class Layout
include Clearwater::Component
include Routing
def render
div([
match('/articles') { Articles.new },
match('/about') { About.new },
miss { Articles.new },
])
end
end
class Articles
include Clearwater::Component
include Routing
def render
MasterDetail.new(
ul(articles.map { |article| ArticlesListItem.new(article) }),
div([
# Matching a dynamic segment could pass the value to the block
match(':article_id') { |article_id| ArticlePage.new(articles[article_id]) },
miss { h2('Please select an article from the left' },
])
)
end
end The If we can make this work, this opens up some really, really cool stuff, like |
That looks good! I'll reopen and rename this issue so others can join in the discussion. I have a rough implementation going at https://github.com/johnsusi/clearwater-crossroads/ It handles the simple cases but currently fails when on nested matches. |
@johnsusi I played around a little with an idea today and got something working, too: https://gist.github.com/jgaskins/50b0bc5f0a8cea038e24d9d29dd66129#file-routing-rb Also included example components using it. It doesn't match dynamic segments yet (that was the hardest part in We might be able to take some inspiration from Roda's router here. |
Here's a full example Clearwater app with dynamic segments working. It's quite naïve atm, only letting you match one path segment (a segment being the part between the slashes in the path) at a time, though Clearwater's own router isn't much better (despite containing much more code). It'll match multiple segments at a time when the match contains no dynamic segments, though. I'm getting a lot more excited about this the more I experiment with it. |
I actually tried using the matcher from rails but I could not get it to work. About nesting, https://github.com/johnsusi/clearwater-crossroads/blob/master/spec/crossroads/match_spec.rb#L70 That should actually work in opal but fails when running specs since the ruby version of the dsl runs the sanitize_content on to_html (ie outside of the routers render-method) |
Another idea i like is to be able to inject the path at render time def render
router( '/foo/bar' ) {
# the matcher would see '/foo/bar' now
match('/foo') # ...
}
end Useful for testing and nesting components that know nothing of each other (except that they use routers) It would also be nice to be able to match on query parameters, and here it might actually be wise to let multiple matchers succeed def render
div([
match('?settings=open') { SettingsPanel.new },
match('?toolbar=open') { Toolbar.new },
])
end but I always have this nagging feeling that why not just do it in code :) def render
div([
SettingsPanel.new if query[:settings] == :open,
Toolbar.new if query[:toolbar] == :open,
])
end |
These are awesome ideas, too. Making the path injectable is a great idea for testing. If we can make this work with query params, that's something it'll have over |
While developing a set of components I was surprised to see that the order of which render was called was not what I was expecting.
Here is a small example
Console output
However when I remove one nested div in Layout the order is reversed.
Console output
Looking at https://github.com/clearwater-rb/clearwater/blob/master/opal/clearwater/component.rb#L55 it is clear why it is working this way. I see no easy fix so perhaps this is just something that needs documenting.
Or do you consider Router to be the only way to nest components properly?
I guess this is not a problem in most usecases.
The text was updated successfully, but these errors were encountered: