Someone having tabs with Seaside html+js cached on localStorage?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Someone having tabs with Seaside html+js cached on localStorage?

Mariano Martinez Peck
Hi guys,

I have an application which is tabbed based...that is, there is a main menu and each menu item opens a new tab in a "workspace". The user can then go to different tabs. Right now, every single click on a tab, does an ajax request and re-renders the "tab contents area". I hate this approach because even if the tab/component hasn't changed anything, every single tab click is a request + re-rendering. Sometimes the tabs are quite some heavy components which takes some time to render. So the application feels slow even when simply moving around tabs. 

To workaround that I was thinking to cache in localStorage each tabs html and then on each click of the tab, do a html() of the "tab contents area" to the html cached for that tab.

That seemed like a good idea but after start trying to implement it, and I found quite some problems already. The main problem is that <scripts> embedded in the html of the tab. That JS is re-executed when I do:

$(''.workspaceTabContents'').empty().html(localStorage[''tabContents'' + clickedTabId ]);  

And that is bad because each time I click on a tab, the JS is executed again and I have side effects. I could workaround this by stripping the <scripts> out. But then i have other problems.

For example, I use bootstrap-select for my selects. When you do $(''.selectpicker'').selectpicker();   that alters the original HTML. So when you click on another tab and you must saved latest HTML of the currently selected tab, :

localStorage[''tabContents'' + previousActiveTabId ] = $(''.workspaceTabContents'').html();

it is the already modified HTML. Yet it has the JS...so it would duplicate my selects... 

And this is just to begin with....

Another idea I had is to NOT cache on localStorage on client side but on server side. So that is, if a user clicks on a tab and does the ajax request, I do not re-render the component in Seaside (avoid all cost of #renderContentOn: etc) but instead  answered a cached HTML+JS.  Of course, here I still pay request, network, etc, but at least I avoid HTML generation. 


So I wonder...has anyone ever did something like this? Note that at the moment I cannot afford going with a client-side UI like angular or whatever. 

Thanks in advance, 

--

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Someone having tabs with Seaside html+js cached on localStorage?

Johan Brichau-2
Hi Mariano,

Why are you not using css visibility? 
This is what we do: render all tabs and use some easy JS scripts to show() and hide() the html that needs to be shown.

Johan

On 10 Mar 2017, at 15:38, Mariano Martinez Peck <[hidden email]> wrote:

Hi guys,

I have an application which is tabbed based...that is, there is a main menu and each menu item opens a new tab in a "workspace". The user can then go to different tabs. Right now, every single click on a tab, does an ajax request and re-renders the "tab contents area". I hate this approach because even if the tab/component hasn't changed anything, every single tab click is a request + re-rendering. Sometimes the tabs are quite some heavy components which takes some time to render. So the application feels slow even when simply moving around tabs. 

To workaround that I was thinking to cache in localStorage each tabs html and then on each click of the tab, do a html() of the "tab contents area" to the html cached for that tab.

That seemed like a good idea but after start trying to implement it, and I found quite some problems already. The main problem is that <scripts> embedded in the html of the tab. That JS is re-executed when I do:

$(''.workspaceTabContents'').empty().html(localStorage[''tabContents'' + clickedTabId ]);  

And that is bad because each time I click on a tab, the JS is executed again and I have side effects. I could workaround this by stripping the <scripts> out. But then i have other problems.

For example, I use bootstrap-select for my selects. When you do $(''.selectpicker'').selectpicker();   that alters the original HTML. So when you click on another tab and you must saved latest HTML of the currently selected tab, :

localStorage[''tabContents'' + previousActiveTabId ] = $(''.workspaceTabContents'').html();

it is the already modified HTML. Yet it has the JS...so it would duplicate my selects... 

And this is just to begin with....

Another idea I had is to NOT cache on localStorage on client side but on server side. So that is, if a user clicks on a tab and does the ajax request, I do not re-render the component in Seaside (avoid all cost of #renderContentOn: etc) but instead  answered a cached HTML+JS.  Of course, here I still pay request, network, etc, but at least I avoid HTML generation. 


So I wonder...has anyone ever did something like this? Note that at the moment I cannot afford going with a client-side UI like angular or whatever. 

Thanks in advance, 

--
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside


_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Someone having tabs with Seaside html+js cached on localStorage?

Esteban A. Maringolo
I guess he's not using visibilty to avoid loading the contents of all
tabs at once.

But once loaded I'd do what Johan suggests, only using show/hide of
each tab content (which is loaded on demand).

A more, maybe overkill solution, would be to save on client side when
was the last time you switched to that particular tab (if you have a
way to identify it), so when the user moves between tabs you don't
force an update unless there was certain time since the last update (1
m, 5m, whatever) or, of course, it was the first time you opened the
tab. This way if the click occurs before the update threshold, then
you simply perform a show() on the clicked tab and hide all the
others, if not then you AJAX load its updated contents.

This would have the drawback of having a bigger DOM in the memory of
the client, since each tab, once opened, will remain in the DOM until
closed. But even with a big DOM tree, browsers are optimized for such
scenarios.

Regards,

Esteban A. Maringolo


2017-03-10 12:14 GMT-03:00 Johan Brichau <[hidden email]>:

> Hi Mariano,
>
> Why are you not using css visibility?
> This is what we do: render all tabs and use some easy JS scripts to show()
> and hide() the html that needs to be shown.
>
> Johan
>
> On 10 Mar 2017, at 15:38, Mariano Martinez Peck <[hidden email]>
> wrote:
>
> Hi guys,
>
> I have an application which is tabbed based...that is, there is a main menu
> and each menu item opens a new tab in a "workspace". The user can then go to
> different tabs. Right now, every single click on a tab, does an ajax request
> and re-renders the "tab contents area". I hate this approach because even if
> the tab/component hasn't changed anything, every single tab click is a
> request + re-rendering. Sometimes the tabs are quite some heavy components
> which takes some time to render. So the application feels slow even when
> simply moving around tabs.
>
> To workaround that I was thinking to cache in localStorage each tabs html
> and then on each click of the tab, do a html() of the "tab contents area" to
> the html cached for that tab.
>
> That seemed like a good idea but after start trying to implement it, and I
> found quite some problems already. The main problem is that <scripts>
> embedded in the html of the tab. That JS is re-executed when I do:
>
> $(''.workspaceTabContents'').empty().html(localStorage[''tabContents'' +
> clickedTabId ]);
>
> And that is bad because each time I click on a tab, the JS is executed again
> and I have side effects. I could workaround this by stripping the <scripts>
> out. But then i have other problems.
>
> For example, I use bootstrap-select for my selects. When you do
> $(''.selectpicker'').selectpicker();   that alters the original HTML. So
> when you click on another tab and you must saved latest HTML of the
> currently selected tab, :
>
> localStorage[''tabContents'' + previousActiveTabId ] =
> $(''.workspaceTabContents'').html();
>
> it is the already modified HTML. Yet it has the JS...so it would duplicate
> my selects...
>
> And this is just to begin with....
>
> Another idea I had is to NOT cache on localStorage on client side but on
> server side. So that is, if a user clicks on a tab and does the ajax
> request, I do not re-render the component in Seaside (avoid all cost of
> #renderContentOn: etc) but instead  answered a cached HTML+JS.  Of course,
> here I still pay request, network, etc, but at least I avoid HTML
> generation.
>
>
> So I wonder...has anyone ever did something like this? Note that at the
> moment I cannot afford going with a client-side UI like angular or whatever.
>
> Thanks in advance,
>
> --
> Mariano
> http://marianopeck.wordpress.com
> _______________________________________________
> seaside mailing list
> [hidden email]
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
>
>
> _______________________________________________
> seaside mailing list
> [hidden email]
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Someone having tabs with Seaside html+js cached on localStorage?

Mariano Martinez Peck
In reply to this post by Johan Brichau-2


On Fri, Mar 10, 2017 at 12:14 PM, Johan Brichau <[hidden email]> wrote:
Hi Mariano,

Why are you not using css visibility? 
This is what we do: render all tabs and use some easy JS scripts to show() and hide() the html that needs to be shown.


Thanks Johan,

I haven't thought about that one. Seems like a good idea. Let me ask...when you need to open a new tab (say a main menu button was clicked), how do you avoid having to re-render all the "workspace" (all tabs) ?  Do you only render the new one and do an append() or something?

Thanks in advance,
 
Johan

On 10 Mar 2017, at 15:38, Mariano Martinez Peck <[hidden email]> wrote:

Hi guys,

I have an application which is tabbed based...that is, there is a main menu and each menu item opens a new tab in a "workspace". The user can then go to different tabs. Right now, every single click on a tab, does an ajax request and re-renders the "tab contents area". I hate this approach because even if the tab/component hasn't changed anything, every single tab click is a request + re-rendering. Sometimes the tabs are quite some heavy components which takes some time to render. So the application feels slow even when simply moving around tabs. 

To workaround that I was thinking to cache in localStorage each tabs html and then on each click of the tab, do a html() of the "tab contents area" to the html cached for that tab.

That seemed like a good idea but after start trying to implement it, and I found quite some problems already. The main problem is that <scripts> embedded in the html of the tab. That JS is re-executed when I do:

$(''.workspaceTabContents'').empty().html(localStorage[''tabContents'' + clickedTabId ]);  

And that is bad because each time I click on a tab, the JS is executed again and I have side effects. I could workaround this by stripping the <scripts> out. But then i have other problems.

For example, I use bootstrap-select for my selects. When you do $(''.selectpicker'').selectpicker();   that alters the original HTML. So when you click on another tab and you must saved latest HTML of the currently selected tab, :

localStorage[''tabContents'' + previousActiveTabId ] = $(''.workspaceTabContents'').html();

it is the already modified HTML. Yet it has the JS...so it would duplicate my selects... 

And this is just to begin with....

Another idea I had is to NOT cache on localStorage on client side but on server side. So that is, if a user clicks on a tab and does the ajax request, I do not re-render the component in Seaside (avoid all cost of #renderContentOn: etc) but instead  answered a cached HTML+JS.  Of course, here I still pay request, network, etc, but at least I avoid HTML generation. 


So I wonder...has anyone ever did something like this? Note that at the moment I cannot afford going with a client-side UI like angular or whatever. 

Thanks in advance, 

--
_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside


_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside




--

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Someone having tabs with Seaside html+js cached on localStorage?

Paul DeBruicker
jQuery has .one() which calls the function only once.   You could use that to load your tab content on the first click

https://api.jquery.com/one/







Mariano Martinez Peck wrote
On Fri, Mar 10, 2017 at 12:14 PM, Johan Brichau <[hidden email]> wrote:

> Hi Mariano,
>
> Why are you not using css visibility?
> This is what we do: render all tabs and use some easy JS scripts to show()
> and hide() the html that needs to be shown.
>
>
Thanks Johan,

I haven't thought about that one. Seems like a good idea. Let me ask...when
you need to open a new tab (say a main menu button was clicked), how do you
avoid having to re-render all the "workspace" (all tabs) ?  Do you only
render the new one and do an append() or something?

Thanks in advance,


> Johan
>
> On 10 Mar 2017, at 15:38, Mariano Martinez Peck <[hidden email]>
> wrote:
>
> Hi guys,
>
> I have an application which is tabbed based...that is, there is a main
> menu and each menu item opens a new tab in a "workspace". The user can then
> go to different tabs. Right now, every single click on a tab, does an ajax
> request and re-renders the "tab contents area". I hate this approach
> because even if the tab/component hasn't changed anything, every single tab
> click is a request + re-rendering. Sometimes the tabs are quite some heavy
> components which takes some time to render. So the application feels slow
> even when simply moving around tabs.
>
> To workaround that I was thinking to cache in localStorage each tabs html
> and then on each click of the tab, do a html() of the "tab contents area"
> to the html cached for that tab.
>
> That seemed like a good idea but after start trying to implement it, and I
> found quite some problems already. The main problem is that <scripts>
> embedded in the html of the tab. That JS is re-executed when I do:
>
> $(''.workspaceTabContents'').empty().html(localStorage[''tabContents'' +
> clickedTabId ]);
>
> And that is bad because each time I click on a tab, the JS is executed
> again and I have side effects. I could workaround this by stripping the
> <scripts> out. But then i have other problems.
>
> For example, I use bootstrap-select for my selects. When you do
> $(''.selectpicker'').selectpicker();   that alters the original HTML. So
> when you click on another tab and you must saved latest HTML of the
> currently selected tab, :
>
> localStorage[''tabContents'' + previousActiveTabId ] =
> $(''.workspaceTabContents'').html();
>
> it is the already modified HTML. Yet it has the JS...so it would duplicate
> my selects...
>
> And this is just to begin with....
>
> Another idea I had is to NOT cache on localStorage on client side but on
> server side. So that is, if a user clicks on a tab and does the ajax
> request, I do not re-render the component in Seaside (avoid all cost of
> #renderContentOn: etc) but instead  answered a cached HTML+JS.  Of course,
> here I still pay request, network, etc, but at least I avoid HTML
> generation.
>
>
> So I wonder...has anyone ever did something like this? Note that at the
> moment I cannot afford going with a client-side UI like angular or
> whatever.
>
> Thanks in advance,
>
> --
> Mariano
> http://marianopeck.wordpress.com
> _______________________________________________
> seaside mailing list
> [hidden email]
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
>
>
> _______________________________________________
> seaside mailing list
> [hidden email]
> http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
>
>


--
Mariano
http://marianopeck.wordpress.com

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Someone having tabs with Seaside html+js cached on localStorage?

Johan Brichau-2
In reply to this post by Mariano Martinez Peck

On 10 Mar 2017, at 16:34, Mariano Martinez Peck <[hidden email]> wrote:

I haven't thought about that one. Seems like a good idea. Let me ask...when you need to open a new tab (say a main menu button was clicked), how do you avoid having to re-render all the "workspace" (all tabs) ?  Do you only render the new one and do an append() or something?

The easiest is when you _can_ render all tabs at once, but if that gets to heavy (as Esteban is mentioning), you should do it lazily, which means doing ajax requests when necessary.
I cannot really copy/paste any code for this, but let me try to outline what I would do:

- Each of the tabs should be Seaside components, nested inside a ‘window’ component that holds onto all the tabs.
- When you render the page, the ‘window’ component renders the open tab and does not render anything for the others.
- The tab controls are implemented using javascript and when you click a new tab, this code checks if the tab is on the page and if it’s not it asks the server to render it via an ajax request and appends the generated html to the page in the correct location, followed by a hide() and show().
- One way we do this is generate <div> elements with a unique id that identifies the tab component. If the div is empty, we launch a callback with the id as an argument and our Seaside component then knows which component to render. That just requires you to keep a dictionary of components in the ‘window’ component with mappings id -> tab component.

So… basically what you already had in mind, but using the DOM as the place to store the tab html instead of somewhere else.

My guess is that the hardest problem is to know when you need to rerender a tab’s html (based on changes on the server…) instead of just showing the content already on the page.

Johan

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside
Reply | Threaded
Open this post in threaded view
|

Re: Someone having tabs with Seaside html+js cached on localStorage?

Mariano Martinez Peck


On Fri, Mar 10, 2017 at 2:56 PM, Johan Brichau <[hidden email]> wrote:

On 10 Mar 2017, at 16:34, Mariano Martinez Peck <[hidden email]> wrote:

I haven't thought about that one. Seems like a good idea. Let me ask...when you need to open a new tab (say a main menu button was clicked), how do you avoid having to re-render all the "workspace" (all tabs) ?  Do you only render the new one and do an append() or something?

The easiest is when you _can_ render all tabs at once, but if that gets to heavy (as Esteban is mentioning), you should do it lazily, which means doing ajax requests when necessary.
I cannot really copy/paste any code for this, but let me try to outline what I would do:

- Each of the tabs should be Seaside components, nested inside a ‘window’ component that holds onto all the tabs.
- When you render the page, the ‘window’ component renders the open tab and does not render anything for the others.
- The tab controls are implemented using javascript and when you click a new tab, this code checks if the tab is on the page and if it’s not it asks the server to render it via an ajax request and appends the generated html to the page in the correct location, followed by a hide() and show().
- One way we do this is generate <div> elements with a unique id that identifies the tab component. If the div is empty, we launch a callback with the id as an argument and our Seaside component then knows which component to render. That just requires you to keep a dictionary of components in the ‘window’ component with mappings id -> tab component.

So… basically what you already had in mind, but using the DOM as the place to store the tab html instead of somewhere else.

My guess is that the hardest problem is to know when you need to rerender a tab’s html (based on changes on the server…) instead of just showing the content already on the page.



Thanks Johan,

I ended up doing pretty much all what you suggest above!! And so far it have a working version! Quite easy to do in fact. I still need to fix a fix issues, but your solution was pretty straightforward.

Thanks a lot in advance. 

 
Johan

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside




--

_______________________________________________
seaside mailing list
[hidden email]
http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside