Rendering complete page and not "progressively" (using struts 2 / tiles) - struts2

Is there a way to get struts 2 (using tiles) to build the whole page before sending it to the browser? I don't want the page to be build "progressively" in the browser one part at a time.
The main problem I'm trying to solve is that internet explorer 7 flashes/blinks the page even if only some of the content changes (firefox does this much more smoothly).
So that if I have a page with:
HEADER
some content
FOOTER
And the "some content" area only changes between page loads, the FOOTER part still flashes the white background before filling it with the background color of the footer. I tought that maybe by getting struts to send the complete page it would load fast enough to eliminate the "blinking".
Now the FOOTER comes from the server a little bit later than the parts before it and so it flashes (in internet explorer, firefox displays the page smoothly).
NB: this is an important requirement for the site, and using ajax to load the middle content is out (as are frames or other "hacks"). The site is built using CSS and not a table layout, maybe I will have to use a table layout to get it to work...
About using tiles flush parameter:
I tried that and it doesn't work as I need. I would need a flush-parameter for the whole page. I have tried the normal jsp page directive "autoFlush=false" but it didn't work. I set this directive on my main template page (and not in the tiles).
Here is an example from the main template, which uses header, body and footer templates. With the Thread.sleep() I added the problem is easy to spot. The footer renders 2 secs later than the rest of the page.
<body>
<div id="container">
<t:insertAttribute name="header" flush="false" />
<div id="content"><t:insertAttribute name="body" flush="false"/></div>
<div class="clear"></div>
<% Thread.sleep(2000); %>
<t:insertAttribute name="footer" flush="false" />
</div>
</body>
UPDATE
Thanks for the comments. The requirement is actually almost reasonable as this isn't a normal web page, think embedded.
But apparently there is no way of configuring IE to start rendering after some delay (like firefox has a configurable delay of some 100ms)?
I tried to intercept the TilesResult but the method doExecute is run before the whole content is apparently evaluated, so the method has already exited before the jsp is evaluated (my Thread.sleep() test). I was wondering how I could render the whole response to a string and then output that all at once to the browser.
I know that this isn't foolproof and network delays etc may factor in this, but if I could get the response to output all at once and maybe use a table based layout (IE possibly renders the table only after the table closes) this could work reasonably.
Or then try to get this switched to firefox or maybe forget all about this little glitch...
UPDATE 2
This started to bother me so I did some investigation.
If I had a plain jsp page (no tiles) the buffering works (with the buffer attribute), so that if I had my Thread.sleep() there the whole page rendered after two seconds if the page size was below the buffer size.
But if I used tiles in the page (as in the example above) I couldn't get the page to render at the same time (I even included the page directive in all my tiles-templates/"components", no help). So tiles probably flushes the response somewhere?
Furthermore, the "problematic tiles" was my body-part, which contained a struts:form tag. I replaced it with a normal form-tag and it worked as I wanted...
UPDATE 3
Ok, nobody seems to know the inner workings of tiles or struts tags...
No big problem as this is a very specific case and requirement.
I worked around it by using apache as a proxt in front of the application, and using apache's proxy configuration options to specify a large buffer.
I'll mark this as answered.

You can send page data all at once at the server end if you like (and many frameworks do that anyway for convenience) but the reality of networking is that it won't all arrive at once and the browser will render it as packets arrive. And this is a good thing for responsiveness, even if you* aesthetically would like the page to display all at once.
You can reduce the lag as much as possible by simplifying markup and using deflate compression to keep the payload size down, and that's a worthwhile thing to do in general. Plus you can make sure you're not hitting a Flash Of Unstyled Content. But you can't control when the browser chooses to render, short of doing it all in JavaScript with all the downsides that entails (and even then, the browser might redraw slowly).
(* - or your client/boss, if that's who has come up with this "important requirement" that your site somehow work differently to every other page on the web.)

Can you use the "flush" attribute on the tiles components?
<tiles:insertAttribute name="body" flush="false"/>
In addition if the output buffer gets too big, it will flush anyway. Try increasing the buffer size?
<%# page language="java" buffer="500kb" autoFlush="false" %>

Related

grails fields plugin <f:display is 'chopping off' bootstrap dropright action with a table of values

grails v 3.3.9, fields plugin
fighting with fields plgin and theres a problem when rendering domain objects and using bootstrap
i've got a sample here from a simple standalone page to show the problem
<p>f:display category </p>
<f:display bean="maintenanceAgreement" >
</f:display>
<hr />
<p>f:field category</p>
<f:field bean="${this.pageScope.maintenanceAgreement}" property="category">
<g:render template="/_fields/map/displayWidget" ></g:render>
</f:field>
<hr />
in essenence i have added a template in "/_fields/map/displayWidget" that renders a drop right table on a button
when you render a map field directly from your Domain object the sample table opens and you get all of the table
however when you
you can see the differences between using f.display (has clipping problem), f.field ( which seems to work) and f.all that ignores my _fields/map/_displayWidget.gsp
I dont want to have not use the fields plugin but its not working with bootstrap templating
has any one come up with a fix for this problem?
the project demo page is here
github standalone page to show rendering problem
the attached shows the output as you try each and select category property
well goldarn it another 2 days down the pan - but i have it !
I thought at first it was something to do with fields plugin processing. so i hacked a clone of plugin project locally and added some bits so i could watch it/debug step through it
in doing so i noted that my dummy web domain class page i'd cut across to the plugin didnt have the clipping problem. but the styles were not the same so i copied main.css and grails.css from ordinary project back into the plugin, then re rendered in the browser - and the clipping happened again.
so its in the css!. some very careful watching of browser and looking at the browser 'inspect' indicated that the clipping seemed to be enabled very early on in the journey.
so in my dummy page i just used
I then spent a day wandering round the various bits of fields plugin as its not that well explained anywhere.
if you look at the plugins taglib display method, by default that triggers the /templates/fields/_list.gsp. naming is a little odd but its the gsp that renders the domains persistent attributes as an ordered list - the plugins default _list.gsp looks like this
<ol class="property-list ${domainClass.decapitalizedName}">
<g:each in="${domainProperties}" var="p">
<li class="fieldcontain">
<span id="${p.name}-label" class="property-label"><g:message code="${domainClass.decapitalizedName}.${p.name}.label" default="${p.defaultLabel}" /></span>
<div class="property-value" aria-labelledby="${p.name}-label">${body(p)}</div>
</li>
</g:each>
</ol>
so after much exploration coming up through templates, from the bottom I ended up right at the top with the '
so nearly there now. back into main.css that i'd copied in. if you edit that, down around line 215 you get this style. If you comment out the overflow property - its all fixed !
.property-list .fieldcontain {
list-style: none;
/*overflow: hidden; */
zoom: 1;
}
I tried auto, scroll, and visible but that seems to much about with too much of the page so best to just comment it out.
once you do that - the rest of the rendering of your forms starts to work !! blimey one line of css for all that pain. Attached is the page using
Lastly through out all this, id ended up digging through /tracing fields plugin. What a nest that is. Not really finished here, but basically
with no body just renders a label and no content. So you either need to provide provide a body tag, say to get the value field displayed.
as
if no widget template has been defined then the renderDefaultDisplay is called which again has very limited options for controlling the rendering by falling through a 'switch (prop.type)' and basically calls either g.format (bool), g.formatDate (but no LocalDateTime/LocalDate Support) or g.fieldValue, non of which are bootstrap enabled.
if you call
these two diagrams are not beautiful but just high level pseudo code walk through for what the core tags are trying to do. One day i'll try and pretty that up but it might help you if you get stuck
I'll raise a bug for the main.css clipping directly to the grails team and see what happens, but you can comment the line out yourself if you fall foul of it.

React Component not rendered properly with Turbolinks in Rails 5.1

I have a very simple Rails app with a react component that just displays "Hello" in an existing div element in a particular page (let's say the show page).
When I load the related page using its URL, it works. I see Hello on the page.
However, when I'm previously on another page (let's say the index page and then I go to the show page using Turbolinks, well, the component is not rendered, unless I go back and forth again. (going back to the index Page and coming back to the show page)
From here every time I go back and forth, I can say that the view is rendered twice more time.Not only twice but twice more time! (i.e. 2 times then 4, then 6 etc..)
I know that since in the same time I set the content of the div I output a message to the console.
In fact I guess that going back to the index page should still run the component code without the display since the div element is not on the index page. But why in a cumulative manner?
The problems I want to solve are:
To get the code run on the first request of the show page
To block the code from running in other pages (including the index page)
To get the code run once on subsequent requests of the show page
Here the exact steps and code I used (I'll try to be as concise as possible.)
I have a Rails 5.1 app with react installed with:
rails new myapp --webpack=react
I then create a simple Item scaffold to get some pages to play with:
rails generate scaffold Item name
I just add the following div element in the Show page (app/views/items/show.html.erb):
<div id=hello></div>
Webpacker already generated a Hello component (hello_react.jsx) that I modified as following in ordered to use the above div element. I changed the original 'DOMContentLoaded' event:
document.addEventListener('turbolinks:load', () => {
console.log("DOM loaded..");
var element = document.getElementById("hello");
if(element) {
ReactDOM.render(<Hello name="React" />, element)
}
})
I then added the following webpack script tag at the bottom of the previous view (app/views/items/show.html.erb):
<%= javascript_pack_tag("hello_react") %>
I then run the rails server and the webpack-dev-server using foreman start (installed by adding gem 'foreman' in the Gemfile) . Here is the content of the Procfile I used:
web: bin/rails server -b 0.0.0.0 -p 3000
webpack: bin/webpack-dev-server --port 8080 --hot
And here are the steps to follow to reproduce the described behavior:
Load the index page using the URL http://localhost:3000/items
Click New Item to add a new item. Rails redirects to the item's show page at the URL localhost:3000/items/1. Here we can see the Hello React! message. It works well!
Reload the index page using the URL http://localhost:3000/items. The item is displayed as expected.
Reload the show page using the URL http://localhost:3000/items/1. The Hello message is displayed as expected with one console message.
Reload the index page using the URL http://localhost:3000/items
Click to the Show link (should be performed via turbolink). The message is not shown neither the console message.
Click the Back link (should be performed via turbolink) to go to the index page.
Click again to the Show link (should be performed via turbolink). This time the message is well displayed. The console message for its part is shown twice.
From there each time I go back to the index and come back again to the show page displays two more messages at the console each time.
Note: Instead of using (and replacing) a particular div element, if I let the original hello_react file that append a div element, this behavior is even more noticeable.
Edit: Also, if I change the link_to links by including data: {turbolinks: false}. It works well. Just as we loaded the pages using the URLs in the browser address bar.
I don't know what I'm doing wrong..
Any ideas?
Edit: I put the code in the following repo if interested to try this:
https://github.com/sanjibukai/react-turbolinks-test
This is quite a complex issue, and I am afraid I don't think it has a straightforward answer. I will explain as best I can!
To get the code run on the first request of the show page
Your turbolinks:load event handler is not running because your code is run after the turbolinks:load event is triggered. Here is the flow:
User navigates to show page
turbolinks:load triggered
Script in body evaluated
So the turbolinks:load event handler won't be called (and therefore your React component won't be rendered) until the next page load.
To (partly) solve this you could remove the turbolinks:load event listener, and call render directly:
ReactDOM.render(
<Hello name="React" />,
document.body.appendChild(document.createElement('div'))
)
Alternatively you could use <%= content_for … %>/<%= yield %> to insert the script tag in the head. e.g. in your application.html.erb layout
…
<head>
…
<%= yield :javascript_pack %>
…
</head>
…
then in your show.html.erb:
<%= content_for :javascript_pack, javascript_pack_tag('hello_react') %>
In both cases, it is worth nothing that for any HTML you add to the page with JavaScript in a turbolinks:load block, you should remove it on turbolinks:before-cache to prevent duplication issues when revisiting pages. In your case, you might do something like:
var div = document.createElement('div')
ReactDOM.render(
<Hello name="React" />,
document.body.appendChild(div)
)
document.addEventListener('turbolinks:before-cache', function () {
ReactDOM.unmountComponentAtNode(div)
})
Even with all this, you may still encounter duplication issues when revisiting pages. I believe this is to do with the way in which previews are rendered, but I have not been able to fix it without disabling previews.
To get the code run once on subsequent requests of the show page
To block the code from running in other pages (including the index page)
As I have mentioned above, including page-specific scripts dynamically can create difficulties when using Turbolinks. Event listeners in a Turbolinks app behave very differently to that without Turbolinks, where each page gets a new document and therefore the event listeners are removed automatically. Unless you manually remove the event listener (e.g. on turbolinks:before-cache), every visit to that page will add yet another listener. What's more, if Turbolinks has cached that page, a turbolinks:load event will fire twice: once for the cached version, and another for the fresh copy. This is probably why you were seeing it rendered 2, 4, 6 times.
With this in mind, my best advice is to avoid adding page-specific scripts to run page-specific code. Instead, include all your scripts in your application.js manifest file, and use the elements on your page to determine whether a component gets mounted. Your example does something like this in the comments:
document.addEventListener('turbolinks:load', () => {
var element = document.getElementById("hello");
if(element) {
ReactDOM.render(<Hello name="React" />, element)
}
})
If this is included in your application.js, then any page with a #hello element will get the component.
Hope that helps!
I was struggling with similar problem (link_to helper method was changing URL but react content was not loaded; had to refresh page manually to load it properly). After some googling I've found simple workaround on this page.
<%= link_to "Foo", new_rabbit_path(#rabbit), data: { turbolinks: false } %>
Since this causes a full page refresh when the link is clicked, now my react pages are loaded properly. Maybe you will find it useful in your project as well :)
Upon what you said I tested some code.
First, I simply pull out the ReactDOM.render method from the listener as you suggested in your first snippet.
This provide a big step forward since the message is no longer displayed elsewhere (like in the index page) but only in the show page as wanted.
But something interesting happen in the show page. There is no more accumulation of the message as appended div element, which is good. In fact it's even displayed once as wanted. But.. The console message is displayed twice!?
I guess that something related to the caching mechanism is going on here, but since the message is supposed to be appended why it isn't displayed twice as the console message?
Putting aside this issue, this seems to work and I wonder why it's necessary in the first place to put the React rendering after the page is loaded (without Turbolinks there was the DOMContentLoaded event listener)?
I guess that this has do with unexpected rendering by javascript code executed when some DOM elements are yet to be loaded.
Then, I tried your alternative way using <%= content_for … %>/<%= yield %>.
And as you expected this give mitigate results ans some weird behavior.
When I load via the URL the index page and then go to the show page using the Turbolink, it works!
The div message as well as the console message are shown once.
Then if I go back (using Turbolink), the div message is gone and I got the ".. unmounted.." console message as wanted.
But from then on, whenever I go back to the show page, the div and the console message are both never displayed at all.
The only message that's displayed is the ".. unmounted.." console message whenever I go back to the index page.
Worse, if I load the show page using the URL, the div message is not displayed anymore!? The console message is displayed but I got an error regarding the div element (Cannot read property 'appenChild' of null).
I will not deny that I completely ignore what's happening here..
Lastly, I tried your last best advice and simply put the last code snippet in the HTML head.
Since this is jsx code, I don't know how to handle it within the Rails asset pipeline / file structure, so I put my javascript_pack_tag in the html head.
And indeed, this works well.
This time the code is executed everywhere so it makes sense to use page-specific element (as previously intended in the commented code).
The downside, is that this time the code could be messy unless I put all page-specific code inside if statements that test for the presence of the page-specific element.
However since Rails/Webpack has a good code structure, it should be easily manageable to put page-specific code into page-specific jsxfiles.
Nevertheless the benefit is that this time all the page-specific parts are rendered at the same time as the whole page, thus avoiding a display glitch that occurs otherwise.
I didn't address this issue at the first place, but indeed, I would like to know how to get page specific contents rendered at the same time as the whole page.
I don't know if this is possible when combining Turbolink with React (or any other framework).
But in conclusion I leave this question for later on.
Thank you for your contribution Dom..

How can I make code indentation behave correctly in vbhtml razor files?

This is driving me round the bend. I'm a long time VB.NET forms developer, quite new to ASP.NET and completely new to MVC. I'm creating vbhtml pages that use the VB.NET Razor syntax, and I seem to be constantly fighting against the UI which is trying to indent my code incorrectly. Take the following example, based on the template page for a new Razor view:
#Code
Layout = Nothing
End Code
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div>
#If True Then
#<ul>
#For x = 1 To 2
Next
</ul>
End If '<-- Randomly indented too far
</div>
</body>
</html>
In the above example, as soon as I hit return after Next, End If two lines below randomly jumps two tabs forward from where it should be. In other examples I've hit a circle where pushing one line to the correct place throws another line out of position and vice versa.
I'm so annoyed at this point I'd be happy to disable auto-indentation completely and just manage it myself, but I can't even find out how to do that! Following advice on another thread I disabled indentation for HTML pages but all that stops is indentation of HTML tags - the code blocks still slide around all over the place.
I thought an extension might be causing the problem but I disabled them all and restarted and the problem remains. Am I doing something fundamentally wrong? I find it hard to believe Microsoft would release something so poor so it seems more likely I'm just not using it right.
I found a solution (of a fashion) on another question (I really did search hard before posting this question and couldn't find anything): Why doesn't Visual Studio code formatting work properly for Razor markup?
Essentially the solution seems to be to ensure that your code uses spaces instead of tabs for the whitespace. Whilst increasing the overall size of the page because of increased whitespace, it does lessen the problem (whilst not eliminating it completely). On the linked thread, someone who appears to be connected with Microsoft has acknowledged it is indeed a bug related to the overlapping formatters for HTML and VB.NET which they hope to improve in a new release. I've dropped to 2 spaces per indent to lessen the bandwidth impact.
Thanks to the guys who contributed.
A better alternative here(rather than using spaces for tabs), is to change the block indenting for HTML and C#/VB to "Block" instead of "Smart". This isn't a full solution, but IMO is a far less painful work-around than using spaces!

Slowness in Orbeon page rendering when showing a group with a large number of fields

I am working on Orbeon forms and i have a performance related issue as explained below.
I have a form where I have five fields initially. On the fifth dropdown field, if I select "Yes", because of xforms:group it shows a block of fields (the block has around 40 fields).
Since the block is in the repeated section, I can add/delete as many blocks as I can.
Now, if I add say 10 blocks and when I toggle the fifth dropdown field from any value to "Yes", it takes more than 2 seconds to display all the blocks.
I am using Orbeon Forms 3.8 and Tomcat 6 on Windows XP desktop with 2GB RAM.
Please let me know what happens when "Yes" is selected (meaning conditional display when xforms:group is true) which is taking more time to display.
<xforms:group ref=".[instance('form-attributes')/flag='yes']" >
//code for the controls here
</xforms:group>
If you are using code that looks like:
<xforms:group ref=".[condition]">
<!-- Large number of fields -->
</xforms:group>
When condition is false, the fields inside the group are non-relevant. The XForms engine doesn't compute their value, read-only status, validity, label, hint, help, alert, etc.
When condition becomes true, the content of the group become relevant, and the XForms engine evaluates all the controls inside the group.
The browser needs to apply all those changes to the DOM.
Typically, step #2 is much faster than #3, especially with IE7. To avoid the numerous updates on step #3, another way to write this code is:
<xhtml:div class="{if (condition) then '' else 'xforms-disabled'}">
<!-- Large number of fields -->
</xhtml:div>
With this, the fields inside the div will always be relevant:
The upside is that when condition becomes true, all the browser might need to do is to flip that class on the div. It won't necessarily need to update all the controls inside, unless of course their value has also changed.
The downside is that while condition is false, the XForms engine, on the server, needs to keep all the controls inside the div up-to-date.
But more often than not, especially when you're seeing IE7 slowness, the performance you gain on the client far outweighs the increased processing that might be needed on the server.
I found this link that seems to suggest span tag instead of div tag, though the original post was for Code crash, the suggested work around gave a small performance improvement in my form when I tested it in IE. Hope this code will give you some benefit.

Firefox 4 doesn't render partial pages

I have an ASP.NET MVC page which contains a table, where every row takes some time to load. So I'm calling Response.Flush() after every row is rendered.
IE9 behaves the way it should: displays rows one by one. FF4 on the other hand, displays the page only when it finished loading completely, even though I can see in FireBug's Network tab that the rows are being received one by one.
Is there something I could be doing wrong on the server-side? If not, is there something I can do to my Firefox, so that it displays the page the way I want?
I would try using AJAX to fill the table. Maybe a row per call, maybe whole set at once.
Consider closing your document with </html> and add the extra rows in script; <script> tags may (in practice) follow </html>. Not a real AJAX solution, not strictly correct, but potentially a lot easier on your serverside.
A similar, but more correct solution would be to insert the script just before the </body>.
See also When does reflow happen in a DOM environment?

Resources