Best practice vs javascript in module templates
Posted: Fri May 09, 2014 1:18 pm
It's generally accepted best practice to load javascripts after the content of your page. Which is fine until you have a module that by default inserts javascript in its template. If you haven't pre-loaded any dependencies, eg jQuery in the head section, you're up the creek.
My solution is to load all dependencies esp jQuery as per 'best practice' after the content. Then in the module template, capture the script into an array and add it after the dependency. Eg:
In my module template:
Then in my page template immediately above the <__body> tag:
This drops all module template js (or hidden popup divs etc) at the bottom of the page.
All worked well until this week I tried it with CGGoogleMaps2. Sure, the script went to the bottom of the page but so did the displayed map!
Solution was to on my page:
and in the map template:
Note the "obj.detach().appendTo('.maintext'); line.
The important things above were that the module was executed in the page so all the vars were filled, then in the script, the displayed map gets moved from below the page to the right place within the content with '.maintext' class .
Everything we do is a compromise and it's been said before that {capture} is not hugely efficient. On the other hand, the output scores way higher on page audits using the above technique.
Just saying...
psy
My solution is to load all dependencies esp jQuery as per 'best practice' after the content. Then in the module template, capture the script into an array and add it after the dependency. Eg:
In my module template:
Code: Select all
{capture assign=js}
{literal}
<__script__>
$(document).ready(function()({
...
});
</__script>
{/literal}
{/capture}
{append var=pagejs value=$js}
Code: Select all
<__script__ src="source/to/jquery"></__script>
{if is_array($pagejs)}
{foreach from=$pagejs item=js}
{$js}
{/foreach}
{/if}
All worked well until this week I tried it with CGGoogleMaps2. Sure, the script went to the bottom of the page but so did the displayed map!
Solution was to on my page:
Code: Select all
{capture assign=js}{CGGoogleMaps2 map='mymap'}{/capture}{append var=pagejs value=$js}
Code: Select all
{* map template *}
<__script__ src="http://maps.google.com/maps/api/js?libraries=geometry{if $map->sensor}&sensor=true{else}&sensor=false{/if}"></__script>
<__script__ src="{$mod->GetModuleURLPath()}/lib/js/infobox_packed.js"></__script>
<__script__ src="{$mod->GetModuleURLPath()}/lib/js/map_tooltip.js"></__script>
<__script__ src="{$mod->GetModuleURLPath()}/lib/js/jquery.cggm_map.js"></__script>
<div id="cggm_map_{$mapinstance}" class="col-sm-12 cgmap"></div>
{if $map->directions}
{* enable directions *}
{$generator->get_directions_form()}
{/if}
{* javascript is on the bottom incase some smarty variables we need were set in the various generator calls *}
<__script__ type="text/javascript">
if( typeof(jQuery) == 'undefined' ) {
var div = document.getElementById('cggm_map_{$mapinstance}').
div.innerHTML = '<h3 style="color: red;">jQuery and jQuery UI Are Required</h3>';
throw new Error('jQuery and jQuery UI Are Required');
}
$(document).ready(function(){
var obj = $('#cggm_map_{$mapinstance}');
obj.cggm2({$generator->get_map_options_js()});
{if $map->directions && isset($directions_form_id)}$obj.cggm2('options','directions_form','#{$directions_form_id}');{/if}
obj.detach().appendTo('.maintext');
});
</__script>
The important things above were that the module was executed in the page so all the vars were filled, then in the script, the displayed map gets moved from below the page to the right place within the content with '.maintext' class .
Everything we do is a compromise and it's been said before that {capture} is not hugely efficient. On the other hand, the output scores way higher on page audits using the above technique.
Just saying...
psy