Custom block - when/where to load javascript

Permalink
Hey guys,
I'm working on a custom block and I have an issue with loading javascript files. I have a particular javascript file that always needs to be loaded for this block. In every custom template, on viewing the block, etc. So initially I had a /js folder in my block folder that auto-loaded the file and this worked fine. However, I started adding custom templates and realized the templates override the block-level js folder so the script I needed was never getting loaded. So one solution was to just copy the block-level js folder into every custom template, but this seemed like a huge pain. Instead I decided to add an on_page_view() function to my controller that loads it, like so:
public function on_page_view(){
    $html = Loader::helper('html');
    $this->addFooterItem($html->javascript('myscript.js', 'mypackage'));
}


And this works, but I just noticed a bug. Right after I try to add a new block the script is never loaded. So after adding the block it just hangs until I refresh the page.

So my question is, is there anywhere I can load javascript files that they will always get loaded (including right after loading a new block) and not have to duplicate the js in every custom template?

Thanks in advance!

-Blake

bbeng89
View Replies: View Best Answer
nebuleu replied on at Permalink Reply
nebuleu
I was facing the same problem.

I use a really dirty solution at the moment, and don't have find a more elegant way to achieve this for now ...
As this is a problem that occurs only when editing, I added something like this to my header theme :

if ($c->isEditMode()) {
   $this->addHeaderItem($html->javascript('myscript.js', 'mypackage'));
}


If someone have a best way, I will be glad to use it :)
bbeng89 replied on at Permalink Reply
bbeng89
Yeah this definitely won't work for me because the plan is to hopefully get this block in the marketplace. So I can't make any modifications to the theme. The "dirty" solution for me I guess is to just require the js files to be copied into each template. I'm really hoping there's a better way though.
mhawke replied on at Permalink Best Answer Reply
mhawke
There are lots of blocks that are not 'active' while in edit mode. They just present a grey background with a message to the effect of 'Block not available in Edit Mode'. As far as I know, any activity that the user does to the block on the page while the page is in edit mode is not saved anyways.
bbeng89 replied on at Permalink Reply
bbeng89
I like this solution, and I think that is what I'm going to go with. I actually forgot that a lot of blocks end up doing this. It seems like it is probably going to be the easiest method to implement and least error prone. Thanks mhawke!
mhawke replied on at Permalink Reply
mhawke
There are lots of blocks that are not 'active' while in edit mode. They just present a grey background with a message to the effect of 'Block not available in Edit Mode'. As far as I know, any activity that the user does to the block on the page while the page is in edit mode is not saved anyways.
JohntheFish replied on at Permalink Reply
JohntheFish
@mhawke's recommendation is the one I mostly use when I have more complex scripts in a block view.

http://www.concrete5.org/documentation/how-tos/developers/prevent-a...

http://www.concrete5.org/documentation/how-tos/designers/format-an-...

The problem always arises with assets actually needed by a block's add and edit dialog. Concrete5 doesn't know what is going to be added a page until the actual add dialog is opened, but on_page_view is run by the rendering of the page, before the add/edit dialog is opened.

In view, this is no problem because the block is known to be on the page, the on_page_view event fires, and the assets are loaded.

During an edit, the same applies for on_page_view. You also get anything in auto.js loaded by the edit dialog.

During an add, on_page_view will not fire for that block because it doesn't exist until the add dialog is saved. However auto.js does get loaded with the add dialog.

Some ways round it, usually used for css needed by an edit or add dialog, but equally applicable to javascript assets.

1. Code the style, link or script elements into (usually the top of) the edit.php or add.php

2. Code similar into a method in the controller that is called back from the add/edit.php.

3. Write a state-aware loader caller in the block controller that it can call from on_block_load, add, edit and view. You need to be careful to call addHeaderItem when is still valid (ie , before headers are output) or use addFooterItem (no use for css).

4. Add script to lazy-load the assets from add/edit.php. There is a c5 provided javascript lazy loader method in ccm.app.

5. Create a small auto.js that lazy loads the assets.

There are many other convoluted variations and combinations of the above. You can see many uses of what in some minds would be poor html/css/javascript design separation in the add/edit dialogs for many marketplace addons (including mine).
JohntheFish replied on at Permalink Reply
JohntheFish
PS. If you have not yet seen it, have a play with Ajax lessons. Many of the principles are the same.
bbeng89 replied on at Permalink Reply
bbeng89
Thanks for all the suggestions! I think I've decided to just go with @mhawkes idea of disabling the block in edit mode. This block is fairly complex and pulls in a lot of data so it is probably best that it is disabled in edit mode. Also the user can't really interact with it in edit mode anyway. I appreciate all your other suggestions though. Later down the road if I have some extra time I might try to implement one of them so that the user can get a preview of the block in edit mode.