Skip to content

Commit 019ee0d

Browse files
author
Nils Henning
committed
[REFACTOR][FEATURE] refactor isolate, render not deferred as default behavior unless deferred or init on is specified
1 parent b930950 commit 019ee0d

File tree

8 files changed

+284
-44
lines changed

8 files changed

+284
-44
lines changed

app/concepts/matestack/ui/core/component/base.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,25 +223,28 @@ def get_children
223223
# rendering.
224224
def add_child(child_class, *args, &block)
225225

226-
# when the child is an async component like shown below, only render its wrapper
226+
# when the child is an async or isolate component like shown below, only render its wrapper
227227
# and skip its content on normal page rendering call indicated by @matestack_skip_defer == true
228228
# Example: async defer: 1000 { plain "I should be deferred" }
229229
# the component will triger a subsequent component rendering call after 1000ms
230230
# the main renderer will then set @matestack_skip_defer to false which allows processing
231231
# the childs content in order to respond to the subsequent component rendering call with
232232
# the childs content. In this case: "I should be deferred"
233233
skip_deferred_child_response = false
234-
if child_class == Matestack::Ui::Core::Async::Async
234+
if child_class == Matestack::Ui::Core::Async::Async #|| child_class == Matestack::Ui::Core::Isolate::Isolate
235235
if args.any? { |arg| arg[:defer].present? } && @matestack_skip_defer == true
236236
skip_deferred_child_response = true
237237
end
238238
end
239-
# same applies for all isolated components, no extra defer option needed
239+
240+
# check only allowed keys are passed to isolated components
240241
if child_class < Matestack::Ui::Core::Isolate::Isolate
241-
skip_deferred_child_response = true
242-
unless args.empty? || args[0].keys.all? { |key| key == :defer || key == :public_options || key == :rerender_on || key == :init_on || key == :rerender_delay }
242+
unless args.empty? || args[0].keys.all? { |key| [:defer, :public_options, :rerender_on, :init_on, :rerender_delay].include? key }
243243
raise "isolated components can only take params in a public_options hash, which will be exposed to the client side in order to perform an async request with these params."
244244
end
245+
# if args.any? { |arg| arg[:init_on].present? } && @matestack_skip_defer == true
246+
# skip_deferred_child_response = true
247+
# end
245248
end
246249

247250
if self.class < Matestack::Ui::Core::Isolate::Isolate

app/concepts/matestack/ui/core/isolate/isolate.haml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22
%div{loading_classes.merge(class: "matestack-isolated-component-container")}
33
%div{loading_classes.merge(class: "loading-state-element-wrapper")}
44
=loading_state_element
5-
%div{loading_classes.merge(class: "matestack-isolated-component-wrapper")}
5+
- unless options[:defer] || options[:init_on]
6+
%div{class: "matestack-isolated-component-wrapper", "v-if": "isolatedTemplate == null", "v-bind:class": "{ 'loading': loading === true }"}
7+
= render_isolated_content
8+
%div{class: "matestack-isolated-component-wrapper", "v-if": "isolatedTemplate != null", "v-bind:class": "{ 'loading': loading === true }"}
69
%v-runtime-template{":template":"isolatedTemplate"}

app/concepts/matestack/ui/core/isolate/isolate.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,20 @@ const componentDef = {
7171
},
7272
mounted: function (){
7373
const self = this
74-
if(this.componentConfig["init_on"] === undefined){
75-
if(self.componentConfig["defer"] != undefined){
74+
console.log('mounted isolated component')
75+
if(this.componentConfig["init_on"] === undefined || this.componentConfig["init_on"] === null){
76+
console.log('Its me')
77+
if(self.componentConfig["defer"] == true || Number.isInteger(self.componentConfig["defer"])){
78+
console.log('I should render deferred')
7679
if(!isNaN(self.componentConfig["defer"])){
7780
self.startDefer()
7881
}
79-
}else{
80-
self.renderIsolatedContent();
82+
else{
83+
self.renderIsolatedContent();
84+
}
85+
}
86+
else {
87+
console.log('I should NOT render deferred')
8188
}
8289
}else{
8390
if(self.componentConfig["defer"] != undefined){

app/concepts/matestack/ui/core/isolate/isolate.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def show
4040

4141
# this method gets called when the isolate vuejs component requests isolated content
4242
def render_isolated_content
43-
render :children
43+
render :children if authorized?
4444
end
4545

4646
def authorized?
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
require_relative "../../../support/utils"
2+
include Utils
3+
4+
describe "Isolate Component defer", type: :feature, js: true do
5+
6+
before :all do
7+
class TouchedElementsCounter
8+
include Singleton
9+
attr_reader :counter
10+
11+
def initialize
12+
@counter = 0
13+
end
14+
15+
def increment
16+
@counter = @counter + 1
17+
end
18+
19+
def reset
20+
@counter = 0
21+
end
22+
end
23+
24+
class SomeIsolatedComponent < Matestack::Ui::IsolatedComponent
25+
register_self_as(:some_isolated_component_2)
26+
27+
def prepare
28+
@counter = TouchedElementsCounter.instance
29+
@foo = "foo from isolated component"
30+
end
31+
32+
def response
33+
@counter.increment
34+
div class: "some-isolated-component" do
35+
@counter.increment
36+
span id: "text", text: "some isolated compenent"
37+
end
38+
end
39+
40+
def authorized?
41+
true
42+
end
43+
end
44+
end
45+
46+
before :each do
47+
TouchedElementsCounter.instance.reset
48+
end
49+
50+
it "is resolved completely independent on the server side if defer true is set" do
51+
class ExamplePage < Matestack::Ui::Page
52+
def prepare
53+
@counter = TouchedElementsCounter.instance
54+
@foo = "bar"
55+
end
56+
57+
def response
58+
@counter.increment
59+
div id: "page-div" do
60+
plain "page!"
61+
@counter.increment
62+
some_isolated_component_2 defer: true
63+
end
64+
end
65+
end
66+
67+
visit "/example"
68+
# the first request resolves the whole page --> counter + 2
69+
# the isolated component requests its content right after mount --> counter + 2
70+
expect(TouchedElementsCounter.instance.counter).to eq 4
71+
expect(page).to have_css('.some-isolated-component')
72+
73+
TouchedElementsCounter.instance.reset
74+
75+
visit "/example?component_class=SomeIsolatedComponent"
76+
expect(page).to have_css('.some-isolated-component')
77+
78+
# the above URL is used within the async request of the isolated component in order to get its content
79+
# only the component itself is resolved on the server side --> counter + 2
80+
expect(TouchedElementsCounter.instance.counter).to eq 2
81+
end
82+
83+
it "is deferred by a given time" do
84+
class ExamplePage < Matestack::Ui::Page
85+
def prepare
86+
@counter = TouchedElementsCounter.instance
87+
@foo = "bar"
88+
end
89+
90+
def response
91+
@counter.increment
92+
div id: "page-div" do
93+
plain "page!"
94+
@counter.increment
95+
some_isolated_component_2 defer: 2000
96+
end
97+
end
98+
end
99+
100+
visit "/example"
101+
# the first request resolves the whole page --> counter + 2
102+
# the isolated component requests its content right after mount --> counter + 2
103+
expect(TouchedElementsCounter.instance.counter).to eq 4
104+
# isolated component should not be rendered directly
105+
expect(page).not_to have_css('.some-isolated-component', wait: 1)
106+
# isolated component should be rendered after 2000ms
107+
expect(page).to have_css('.some-isolated-component', wait: 3)
108+
109+
TouchedElementsCounter.instance.reset
110+
111+
visit "/example?component_class=SomeIsolatedComponent"
112+
expect(page).to have_css('.some-isolated-component')
113+
114+
# the above URL is used within the async request of the isolated component in order to get its content
115+
# only the component itself is resolved on the server side --> counter + 2
116+
expect(TouchedElementsCounter.instance.counter).to eq 2
117+
end
118+
119+
it "is deferred by a given time" do
120+
class ExamplePage < Matestack::Ui::Page
121+
def prepare
122+
@counter = TouchedElementsCounter.instance
123+
@foo = "bar"
124+
end
125+
126+
def response
127+
@counter.increment
128+
div id: "page-div" do
129+
plain "page!"
130+
@counter.increment
131+
some_isolated_component_2
132+
end
133+
end
134+
end
135+
136+
visit "/example"
137+
# the first request resolves the whole page --> counter + 2
138+
# the isolated component should be rendered with the page --> counter + 2
139+
expect(TouchedElementsCounter.instance.counter).to eq 4
140+
expect(page).to have_css('.some-isolated-component')
141+
142+
TouchedElementsCounter.instance.reset
143+
144+
visit "/example?component_class=SomeIsolatedComponent"
145+
expect(page).to have_css('.some-isolated-component')
146+
147+
# the above URL is used within the async request of the isolated component in order to get its content
148+
# only the component itself is resolved on the server side --> counter + 2
149+
expect(TouchedElementsCounter.instance.counter).to eq 2
150+
end
151+
152+
end

0 commit comments

Comments
 (0)