Skip to content

enable usage of async rerender_on on component-level #286

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

Merged
merged 1 commit into from
Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion app/concepts/matestack/ui/core/component/dynamic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def components(&block)
@nodes = Matestack::Ui::Core::ComponentNode.build(self, nil, &block)

@nodes.each do |key, node|
@cells[key] = to_cell(key, node["component_name"], node["config"], node["argument"], node["components"], node["included_config"], node["cached_params"])
@cells[key] = to_cell("#{@component_key}__#{key}", node["component_name"], node["config"], node["argument"], node["components"], node["included_config"], node["cached_params"])
end
end

Expand Down Expand Up @@ -190,6 +190,38 @@ def modifiers
result.join(" ")
end

def render_child_component component_key, current_search_keys_array
if respond_to? :prepare
prepare
end

response

if current_search_keys_array.count > 1
if @nodes.dig(*current_search_keys_array) == nil
rest = []
while @nodes.dig(*current_search_keys_array) == nil
rest << current_search_keys_array.pop
end
node = @nodes.dig(*current_search_keys_array)
cell = to_cell(component_key, node["component_name"], node["config"], node["argument"], node["components"], node["included_config"], node["cached_params"])
begin
return cell.render_child_component component_key, rest.reverse[1..-1]
rescue
return cell.render_content
end
else
node = @nodes.dig(*current_search_keys_array)
cell = to_cell(component_key, node["component_name"], node["config"], node["argument"], node["components"], node["included_config"], node["cached_params"])
return cell.render_content
end
else
node = @nodes[current_search_keys_array[0]]
cell = to_cell(component_key, node["component_name"], node["config"], node["argument"], node["components"], node["included_config"], node["cached_params"])
return cell.render_content
end
end

private

def generate_children_cells
Expand Down
48 changes: 31 additions & 17 deletions app/concepts/matestack/ui/core/page/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,23 +91,9 @@ def show(component_key=nil, only_page=false)
concept(@app_class).call(:show, @page_id, @nodes)
when :render_component
begin
if component_key.include?("__")
keys_array = component_key.gsub("__", "__components__").split("__").map {|k| k.to_s}
page_content_keys = keys_array.select{|key| key.match(/^page_content_/)}
if page_content_keys.any?
keys_array = keys_array.drop(keys_array.find_index(page_content_keys[0])+2)
end
node = @nodes.dig(*keys_array)
cell = to_cell(component_key, node["component_name"], node["config"], node["argument"], node["components"], node["included_config"], node["cached_params"])
return cell.render_content
else
node = @nodes[component_key]
cell = to_cell(component_key, node["component_name"], node["config"], node["argument"], node["components"], node["included_config"], node["cached_params"])
return cell.render_content
end
rescue
raise "Component '#{component_key}' could not be resolved. Notice: Rerendering currently works only on page-level. \
You are therefore currently not able to use 'async' within a component for example!"
render_child_component component_key
rescue => e
raise "Component '#{component_key}' could not be resolved."
end
end
end
Expand All @@ -116,6 +102,34 @@ def page_id
@custom_page_id ||= @page_id
end

def render_child_component component_key
if component_key.include?("__")
keys_array = component_key.gsub("__", "__components__").split("__").map {|k| k.to_s}
page_content_keys = keys_array.select{|key| key.match(/^page_content_/)}
if page_content_keys.any?
keys_array = keys_array.drop(keys_array.find_index(page_content_keys[0])+2)
end
if @nodes.dig(*keys_array) == nil
rest = []
while @nodes.dig(*keys_array) == nil
rest << keys_array.pop
end
node = @nodes.dig(*keys_array)
cell = to_cell(component_key, node["component_name"], node["config"], node["argument"], node["components"], node["included_config"], node["cached_params"])
return cell.render_child_component component_key, rest.reverse[1..-1]
else
node = @nodes.dig(*keys_array)
cell = to_cell(component_key, node["component_name"], node["config"], node["argument"], node["components"], node["included_config"], node["cached_params"])
return cell.render_content
end
else
node = @nodes[component_key]
cell = to_cell(component_key, node["component_name"], node["config"], node["argument"], node["components"], node["included_config"], node["cached_params"])
return cell.render_content
end
end


private

def resolve_isolated_component component_key
Expand Down
2 changes: 0 additions & 2 deletions docs/components/async.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ As the name suggests, the async component allows us to let our components behave

Please be aware that, if not configured otherwise, the async core component does get loaded and displayed on initial pageload!

**the async component currently only works on page-level --> we're working on it in order support the usage of async within a component [#75](https://github.com/basemate/matestack-ui-core/issues/75)**

## Parameters

The async core component accepts the following parameters:
Expand Down
85 changes: 83 additions & 2 deletions spec/usage/components/async_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

describe "Async Component", type: :feature, js: true do

it "Example 1 - Rerender on event" do
it "Example 1 - Rerender on event on page-level" do

class ExamplePage < Matestack::Ui::Page

Expand Down Expand Up @@ -32,7 +32,88 @@ def response
expect(before_content).not_to eq(after_content)
end

it "Example 1.1 - Rerender on event if wrapped in app" do
it "Example 1.1 - Rerender on event on (nested) component-level" do

module Components end
module Components::Some end
module Components::Other end

class ExamplePage < Matestack::Ui::Page

def response
components {
div do
custom_some_component
end
}
end

end

class Components::Some::Component < Matestack::Ui::StaticComponent

def response
components {
div id: "static-content-on-component" do
plain "Component 1: #{DateTime.now.strftime('%Q')}"
end
async rerender_on: "my_event" do
div id: "dynamic-content-on-component" do
plain "Component 1: #{DateTime.now.strftime('%Q')}"
end
end
async rerender_on: "my_other_event" do
custom_other_component
div id: "other-dynamic-content-on-component" do
plain "Component 1: #{DateTime.now.strftime('%Q')}"
end
end
}
end

end

class Components::Other::Component < Matestack::Ui::StaticComponent

def response
components {
div id: "static-content-on-other-component" do
plain "Component 2: #{DateTime.now.strftime('%Q')}"
end
async rerender_on: "my_event" do
div id: "dynamic-content-on-other-component" do
plain "Component 2: #{DateTime.now.strftime('%Q')}"
end
end
async rerender_on: "my_other_event" do
div id: "other-dynamic-content-on-other-component" do
plain "Component 2: #{DateTime.now.strftime('%Q')}"
end
end
}
end

end


visit "/example"

static_content_before = page.find("#static-content-on-component").text
dynamic_content_before = page.find("#dynamic-content-on-component").text
other_dynamic_content_before = page.find("#other-dynamic-content-on-component").text

page.execute_script('MatestackUiCore.matestackEventHub.$emit("my_event")')
# sleep
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Queee?

static_content_after = page.find("#static-content-on-component").text
dynamic_content_after = page.find("#dynamic-content-on-component").text
other_dynamic_content_after = page.find("#other-dynamic-content-on-component").text

expect(static_content_before).to eq(static_content_after)
expect(dynamic_content_before).not_to eq(dynamic_content_after)
expect(other_dynamic_content_before).to eq(other_dynamic_content_after)
end

it "Example 1.2 - Rerender on event on page-level if wrapped in app" do

class Apps::ExampleApp < Matestack::Ui::App

Expand Down