Skip to content

Resolving issue 140 #152

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 2 commits into from
Sep 5, 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
3 changes: 3 additions & 0 deletions app/concepts/matestack/ui/core/async/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ const componentDef = {
}
}
}
if(this.componentConfig["init_show"] == true){
this.showing = true
}
},
beforeDestroy: function() {
const self = this
Expand Down
93 changes: 90 additions & 3 deletions docs/components/async.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ end

**Note:** The `rerender_on` option lets you rerender parts of your UI asynchronously, which is cool. But please consider that, if not configured differently, it a) is **not** _lazily loaded_ and b) does get displayed on initial pageload.

Lazy (or defered) loading is a feature we're working on right now, for details see [here](https://github.com/basemate/matestack-ui-core/issues/58).
Lazy (or defered) loading can be configured like shown [here](#defer).

If you want to hide the async component on initial pageload and display it later on, read below as this option (`show_on`) is already implemented (and can be combined with `rerender_on`)!
If you want to simply hide the async component on initial pageload and display it later on, read below how to use `show_on`, which can be combined with `rerender_on`.

### Show_on

The `show_on` option lets us define an event on which the component gets shown.
The `show_on` option lets us define an event on which the component gets shown. The content is still rendered on init pageload, but simply hidden in the browser until the event is emitted. If you want to have proper deferred loading, please refer to [defer](#defer)

```ruby
async show_on: 'my_event' do
Expand Down Expand Up @@ -66,6 +66,30 @@ async hide_after: 1000 do
end
```

### Shown_on/Hide_on Combination

If you combine `shown_on` and `hide_on`, you can toggel the view state of the `async` component explicitly.

By default, the content is initially hidden until the show event is emitted when `shown_on` is applied.

```ruby
async shown_on: "my_show_event", hide_on: 'my_hide_event' do
div id: 'my-div' do
plain 'You will not see me after the event'
end
end
```

If you want to display the content initially, simply add `init_show: true`

```ruby
async shown_on: "my_show_event", hide_on: 'my_hide_event', init_show: true do
div id: 'my-div' do
plain 'You will not see me after the event'
end
end
```

### Defer

The `defer` option may be used in two ways:
Expand Down Expand Up @@ -203,6 +227,69 @@ end

As expected, the timestamp is only visible _before_ our event was fired and is hidden/invisible _after_ the event!

### Example 3.1: Rerender/Show/Hide Combination for inline editing

Imagine, you want to create an inline edit form. Using a combination of `show_on`, `hide_on`, `init_show:true` and `rerender_on` allows you to implement this easily like shown below:


```ruby
class ExamplePage < Matestack::Ui::Page

def prepare
@my_model = MyModel.find(42)
end

def response
components {
partial :show_value
partial :show_form
}
end

def show_value
partial {
async rerender_on: "item_updated", show_on: "item_updated", hide_on: "update_item", init_show: true do
onclick emit: "update_item" do
plain @my_model.title
end
end
}
end

def show_form
partial {
async rerender_on: "item_updated", show_on: "update_item", hide_on: "item_updated" do
form some_form_config, :include do
form_input key: :title, type: :text
form_submit do
button text: "save"
end
end
onclick emit: "item_updated" do
button text: "abort"
end
end
}
end

def some_form_config
{
for: @my_model,
method: :post,
path: :inline_form_action_path, #or any other rails route
params: {
id: @my_model.id
},
success:{
emit: "item_updated"
}
}
end

end
```
If you click on the attribute value, the form gets shown. After successful form submission, the form gets hidden again and only the simple value is shown.

### Example 4: Hide after show on event

On our example page, we wrap a simple timestamp in an async component and tell it to show up when the event `my_event` gets triggered and be hidden after 1000ms.
Expand Down
18 changes: 18 additions & 0 deletions spec/dummy/app/controllers/my_app_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ def collection
responder_for(Pages::MyApp::Collection)
end

def inline_edit
responder_for(Pages::MyApp::InlineEdit)
end

def some_action
render json: {}, status: :ok
end
Expand All @@ -47,6 +51,20 @@ def form_action
end
end

def inline_form_action
@dummy_model = DummyModel.find(params[:id])
@dummy_model.update(dummy_model_params)
if @dummy_model.errors.any?
render json: {
errors: @dummy_model.errors,
message: "Test Model could not be saved!"
}, status: :unproccessable_entity
else
broadcast "test_model_created"
render json: @dummy_model, status: :created
end
end

def delete_dummy_model
@dummy_model = DummyModel.find(params[:id])
if @dummy_model.destroy
Expand Down
3 changes: 3 additions & 0 deletions spec/dummy/app/matestack/apps/my_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ def navigation_section
transition path: :collection_path do
button text: "Collection"
end
transition path: :inline_edit_path do
button text: "Inline Edit"
end
end
}
end
Expand Down
58 changes: 58 additions & 0 deletions spec/dummy/app/matestack/pages/my_app/inline_edit.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
class Pages::MyApp::InlineEdit < Matestack::Ui::Page

def prepare
@my_model = DummyModel.last
end

def response
components {
heading size: 2, text: "Inline Edit"

partial :show_value
partial :show_form
}
end

def show_value
partial {
async rerender_on: "item_updated", show_on: "item_updated", hide_on: "update_item", init_show: true do
onclick emit: "update_item" do
plain @my_model.title
plain "(click me)"
end
end
}
end

def show_form
partial {
async rerender_on: "item_updated", show_on: "update_item", hide_on: "item_updated" do
form some_form_config, :include do
form_input key: :title, type: :text
form_submit do
button text: "save"
end
end
onclick emit: "item_updated" do
button text: "abort"
end
end
}
end

def some_form_config
{
for: @my_model,
method: :post,
path: :inline_form_action_path,
params: {
id: @my_model.id
},
success:{
emit: "item_updated"
}
}
end


end
4 changes: 4 additions & 0 deletions spec/dummy/app/matestack/pages/my_app/my_first_page.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
class Pages::MyApp::MyFirstPage < Matestack::Ui::Page

def prepare
@my_model = DummyModel.last
end

def response
components {
heading size: 2, text: "This is Page 1"
Expand Down
2 changes: 2 additions & 0 deletions spec/dummy/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@
get 'my_fifth_page', to: 'my_app#my_fifth_page'
get 'my_sixth_page', to: 'my_app#my_sixth_page'
get 'collection', to: 'my_app#collection'
get 'inline_edit', to: 'my_app#inline_edit'

post 'some_action', to: 'my_app#some_action'
post 'form_action', to: 'my_app#form_action'
post 'inline_form_action/:id', to: 'my_app#inline_form_action', as: "inline_form_action"

delete 'delete_dummy_model', to: 'my_app#delete_dummy_model'
end
Expand Down
61 changes: 60 additions & 1 deletion spec/usage/components/async_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,66 @@ def response
expect(page).not_to have_selector "#my-div"
end

it "Example 3 - hide after show on event" do
it "Example 3.1 - Show on / Hide on combination init not shown by default" do

class ExamplePage < Matestack::Ui::Page

def response
components {
async show_on: "my_show_event", hide_on: "my_hide_event" do
div id: "my-div" do
plain "#{DateTime.now.strftime('%Q')}"
end
end
}
end

end

visit "/example"

expect(page).not_to have_selector "#my-div"

page.execute_script('MatestackUiCore.matestackEventHub.$emit("my_show_event")')

expect(page).to have_selector "#my-div"

page.execute_script('MatestackUiCore.matestackEventHub.$emit("my_hide_event")')

expect(page).not_to have_selector "#my-div"
end

it "Example 3.2 - Show on / Hide on combination init shown if configured" do

class ExamplePage < Matestack::Ui::Page

def response
components {
async show_on: "my_show_event", hide_on: "my_hide_event", init_show: true do
div id: "my-div" do
plain "#{DateTime.now.strftime('%Q')}"
end
end
}
end

end

visit "/example"

expect(page).to have_selector "#my-div"

page.execute_script('MatestackUiCore.matestackEventHub.$emit("my_hide_event")')

expect(page).not_to have_selector "#my-div"

page.execute_script('MatestackUiCore.matestackEventHub.$emit("my_show_event")')

expect(page).to have_selector "#my-div"
end


it "Example 3.3 - hide after show on event" do

class ExamplePage < Matestack::Ui::Page

Expand Down
Loading