Javascript to run after page load
Hi,
I am writing a plugin with a form and an input field
<input type="file" id="inputfile" />
I also wrote some javascript with the first line as
var control = document.getElementById("inputfile");
I verified the javascript works:
https://jsfiddle.net/qyvzsvq8/
And then I save it as a .js file in my plugin's "js" folder. But I can't seem to get it working in the Vanilla plugin. Here's what I do:
- At the appropriate place, I put
echo <input type="file" id="inputfile" />. The button shows up on the page correctly. - Inside Base_Render_Before, try to call the javascript using
$Sender->AddJsFile('script-input.js','plugins/ScriptRepoPlugin');. However, this throws an error -- the linevar control = document.getElementById("inputfile");returns null.
I did some digging and this can happen if the javascript is run before the page is loaded. Some people suggested to wrap the .js in
jQuery(document).ready(function($){ ... });
It doesn't work.
Some people suggested to wrap the .js in
window.onload = function() { ... }
It doesn't work.
Some people on Vanilla forums site suggest to run this code:
function YourFunctionHere(&$PageEnd) {
echo '<script type="text/javascript" src="js/filename.js" />'."\n";
}
$Context->AddToDelegate('PageEnd', 'PreRender', 'YourFunctionHere');
But I can't figure out where to put this code. I tried putting it between the $PluginInfo definition and the class definition i.e.class MyPlugin extends Gdn_Plugin {...}, but apparently that is the wrong place.
Gah. Any ideas? I simply want the javascript to run AFTER the page is loaded.
Comments
1. How to create a form
Put this in your plugin to create a page that looks like any other Vanilla page and is accessable under yourforum/vanilla/yourform
public function vanillaController_yourForm_create ($sender, $args) { // Use themes master view. $sender->masterView(); // Add common modules. foreach (c('Modules.Vanilla.Panel') as $module) { // We have to exclude the MeModule here, because it is already added // by the template and it would appear twice otherwise. if ($module != 'MeModule') { $sender->addModule($module); } } $title = t('Custom Form'); // Set page title. (We could have used $sender->setData('Title', $title); $sender->title($title); // This sets the breadcrumb to our current page. $sender->setData('Breadcrumbs', array(array('Name' => $title, 'Url' => 'vanilla/yourform'))); // The real interesting things start here. $sender->Form = new Gdn_Form(); // We check if this function has been called by our form. If not, we have // to set it up and show it. // If it has been called by the form and the [Cancel] button was // pressed, just show the "Goodbye" message. If the values have been // submitted, show the "Look at what you've done" screen. // Check if function call includes post values. If no, we have to show // the form. if (!$sender->Form->IsPostBack()) { $sender->setData('Info', t('YourFormInfo', 'Example for common form elements')); // show our form $sender->Render(parent::getView('form.php')); } else { echo 'Your form has been submitted!'; decho($sender->Form->FormValues()); } }Now you also need a
views/form.phpin your plugin folder.<?php defined('APPLICATION') or die; ?> <!-- first we define some markup --> <h1><?= $this->Data('Title') ?></h1> <div class="Info"><?= $this->Data('Info') ?></div> <?php // this "starts" our form echo $this->Form->Open(); // show errors here, at the top of the form echo $this->Form->Errors(); ?> <div class="P"> <?= $this->Form->Label('This is input type="text"', 'InputExample') ?> <div class="TextBoxWrapper"> <?php echo $this->Form->TextBox( 'InputExample', array( 'MultiLine' => true, 'class' => 'TextBox', 'rows' => 3 ) ); ?> </div> </div> <div class="P"> <?= $this->Form->Button('Submit') ?> <?= $this->Form->Button('Cancel') ?> </div>In order to find out more about the possible form elements, look at class.form.php
(in case you wonder: I'm writing some small example plugins and this is a part of it. That's why it is here so exhaustive)
2. How to load your JavaScript
Put it in a subfolder of your plugin called "js". Then use something like that:
public function base_render_before ($sender) { $sender->AddJsFile('yourscript.js', 'plugins/YourPlugin'); }It will be loaded on every page. If you only need it on special pages use something like
discussionController_render_before3. How to start your script after DOM is ready
$(document).ready(function() { alert('This is executed after all elements are available.'); });@R_J,
WOW! Solved all my problems and then some!
However I have a related question.
For a different purpose, I need to run javascript code after the page loads on the new discussion page (i.e. not on a custom form). I took your working code and tried to make it work inside, say, the
PostController_BeforeBodyInput_Handlerfunction.Inside that function, I tried echoing the relevant html content, and I tried inserting a line saying
$Sender->Render(parent::getView('form.php'));. Both ways actually work in terms of showing the content -- i.e. I can get the elements to show up and they all have the correct html attributes.However still I have the original problem -- the line
var control = document.getElementById("inputfile");(referring to the original post in this thread) returns null. Therefore the javascript is still running before page load, not after. So it cannot find theid='inputfile'attribute because it does not exist at javascript runtime.How do I get some javascript to run after page load, on the New Discussions page not a custom form?
Is it possible?
Thanks mucho!
The answer, again, is:
$(document).ready(function() { alert('This is executed after all elements are available.'); });I guess the ID is not "inputfile". Look at the generated HTML source of a new discussion page for the ID.
I have two thoughts when reading your answer:
First one is just a matter of style. I prefer adding JavaScript not at some event, but at "the first event for the page". This would always be someController_render_before. It feels to me like the head of the page and that's where the script tag will be in the end. But I guess there is no "correct" event for doing so.
The second thought is "WTF? A form in a form!?" I don't know what you are trying to do, but adding a form inside a form is simply wrong. If you tell us what the purpose of all this is, we might be able to come up with a better solution.
Extending an existing form is actually quite simple.