How to include javascript file only once - javascript

I want to give clients an HTML block they can include in their site, and this HTML will contain some table and image, plus a javascript that will make manipulations over the HTML block.
so I give them the HTML :
<a data-theme="1" data-srv="http://localhost:50987/" class="block1" href="http://myserver/payment/Details">outer information</a><script type="text/javascript" src="http://myserver/Scripts/checkout.js"></script>
in checkout.js I have included JQuery if no Jquery exists in document and do manipulation over the element $('a.block1') ... the problem is when someone puts this block of HTML more then once over the same page, I want that the client will not call "checkout.js" more then once,
I've tried declaring global var inside "checkout.js" and check if it's exists, it works good to stop doing the same manipulation more then once but I want to stop the call to JS al together .

Javascript runs after it loads, you can't stop the JS running, if it is referenced multiple times. It won't be loaded multiple times, so the overhead of it running again is basically nil.
To stop the behavior of the javascript happening again, just put the check at the top level of the file, put the rest of the file in the conditional, and write to a global variable to make sure you don't run again.
if (window._your_unique_id === undefined) {
window._your_unique_id = true;
// the rest of your javascript
}
that will mean nothing in the script runs. You can still define whatever you like in that if statement, though if you define functions and variables in there, you may have to explicitly put them on the window object, because they'll otherwise be local (but then, it is bad practice to have anything implicitly defined global anyway, so it shouldn't make any difference if your code is well structured).

Just deploy your code as a module.
Ie.
(function(window){
if(window.CheckoutModule) return;
// now you're certain there's no global module loaded
var CheckoutModule = window.CheckoutModule = {};
// you can, ie, add a jQuery check here.
if('undefined' != typeof jQuery) {
// do your jQuery thing here.
}
return ;
})(window, jQuery);

Related

Qt function runJavaScript() does not execute JavaScript code

I am trying to implement the displaying of a web page in Qt. I chose to use the Qt WebEngine to achieve my task. Here's what I did :
Wrote a sample web page consisting of a empty form.
Wrote a JS file with just an API to create a radio button inside the form.
In my code, it looks like this :
View = new QWebEngineView(this);
// read the js file using qfile
file.open("path to jsFile");
myJsApi = file.Readall();
View->page()->runjavascript (myjsapi);
View->page()->runjavascript ("createRadioButton(\"button1\");");
I find that the runJavaScript() function has no effect on the web page. I can see the web page in the output window, but the radio button I expected is not present. What am I doing wrong?
I think you will have to connect the signal loadFinished(bool) of your page() to a slot, then execute runJavaScript() in this slot.
void yourClass::mainFunction()
{
View = new QWebEngineView(this);
connect( View->page(), SIGNAL(loadFinished(bool)), this, SLOT(slotForRunJS(bool)));
}
void yourClass::slotForRunJS(bool ok)
{
// read the js file using qfile
file.open("path to jsFile");
myJsApi = file.Readall();
View->page()->runJavaScript(myjsapi);
View->page()->runJavaScript("createRadioButton(\"button1\");");
}
I had this problem, runJavascript didn't have any effect. I had to put some html content into the view (with page().setHtml("") before running it.
Check the application output, it might contain JavaScript errors. Even if your JS code is valid, you might encounter the situation where the script is run before DOMContentLoaded event, that is document.readyState == 'loading'. Therefore, the DOM might not be available yet, as well as variables or functions provided by other scripts. If you depend on them for your code to run, when you detect this readyState, either wait for the event or try calling the function later, after a timeout. The second approach with timeout might be needed if you need to get the result of the code execution, as this can be done only synchronously.

Include a javascript file only once in Joomla

now, this question has been asked and answered successfully many times, yet none of the things i try work.
I have tried head.js & require.js libraries
I have also tried
if (!window.unique_name) {
unique_name = true;
//code here..
}
none of which I can get to work (the global variable is always undefined)
the script I am trying to include runs something like this:
//clock.js
clockyTick = function() {
//my code here
}
setInterval(clockyTick, 1000);
the apps that call this script, standalone, work fine.
only when both apps are included on the same page (via calls to PHP require()) they break.
Here is the cause of the problems (I think):
I am building custom web apps on a (Joomla) site and have the requirement of displaying two of my apps on the same page.
Both apps need the same .js file to operate correctly, which works fine when they run standalone, but as soon as both apps are running on the same page (in the admin section) the scripts conflict and stop each other from working
(the script in question is a dynamic clock script that grabs the specialised contents of a div and modifies it to something else)
I think the reason I cannot get aforementioned libraries to work, is the fact that they also are being included twice on the admin page.
is there any way around this, or do I have to bite the bullet and integrate a library into the main Joomla template? (meaning the library is uselessly loaded on every single page, yet only used on 3 of hundreds)
jQuery is also required, separately, on each app..but thankfully I am able to use noConflict to avoid problems there (not ideal)
The joomla way would be to instantiate the document inside your module and unset only the conflicting script as described in this question here just before you load the module's script:
1) get an instance if the document object and remove the js files (you
could do that in a plugin) :
<?php
//get the array containing all the script declarations
$document = JFactory::getDocument();
$headData = $document->getHeadData();
$scripts = $headData['scripts'];
//remove your script, i.e. mootools
unset($scripts['/media/system/js/mootools-core.js']);
unset($scripts['/media/system/js/mootools-more.js']);
$headData['scripts'] = $scripts;
$document->setHeadData($headData);
?>
Or in your case, I think you could try the dirty solution below inside your js files:
//1st module script
var unique_name;
if (unique_name == false || unique_name == null) {
unique_name = true;
//code here..
alert("Included 1st script");
}else{
//do nothing
alert("Not included 1st script")
}
//2nd module script
var unique_name;
if (unique_name == false || unique_name == null) {
unique_name = true;
//code here..
alert("Included 2nd script");
}else{
//do nothing
alert("Not included 2nd script")
}
Here is a DEMO
If you are having conflicts with PHP require(), you can try require_once(). However, as mentioned, that’s not the Joomla way of doing things.

how to apply DRY principle to javascript and query

I've got about 30 web pages, all of them HTML forms. Each page has two or more different form elements - select, input text, checkboxes, text areas - along with various ui elements, popups, form validation etc. I'm trying to refactor the jquery used in the pages to use the DRY principle but am not sure how to do it. Here area few examples of some of the jquery used:
Example Code Block A:
$(".show-tool", _container).mouseover(function() {
$(this).nextAll(":hidden").css('display','block');
});
Example Code Block B:
$(".optional").blur(function(){
if ($(this).val() == '')
{
$(this).addClass('optional');
$(this).val('(Optional)');
}
});
Example Code Block C:
$('.howtoremain').click(function() {
$('.hiddendiv').slideToggle("10000");
if($(this).hasClass('howtoremain')) {
$(this).removeClass('howtoremain').addClass('howtoremain2');
}
else {
$(this).removeClass('howtoremain2').addClass('howtoremain');
}
});
All of these are contained in the document.ready. The actual code list above isn't that relevant. I'm trying to have each HTML page only include the jquery code that is relevant. For example page 1 might use code block A and B. Page 2 might use A,B,C,D,E, and F. Page 3 might use code block C and G. Rather than have one giant document.ready with every code block (which will probably cause bugs at some point anyway if one code block needs to be slightly different than another for the same form element), how do you code this? Have one javascript file per code block also seems lousy, as it would cause multiple hits to the server per page. I think I am trying to get at one big javascript file, but only initialize in the document.ready those functions that are relevant to each page.
In my projects, I have gone over to using multiple JS-Files per module and concatenating them into a closure within a build process. This is similar to what jQuery does in its build process (cf. intro.js, outro.js)
This way, I can use granular, DRY modules in smaller files, then concatenate them. A typical single module file might look like this for your Example B:
( function($) {
var subjects = $('.optional');
if ( subjects.length === 0 ) {
// this is a knockout criteria for this module, thus exit this enclosed function
return;
}
subjects.blur(function(){
if ($(this).val() == '')
{
$(this).addClass('optional');
$(this).val('(Optional)');
}
});
// now use whatever you need to initialise.
})($);
As you can see, I use the outer function not only to keep my scope clean, but much more important, to be able to cancel the module's initialisation as soon as I realise, it is not needed on the current page / event / ... - Of course, you may find several more efficient ways of determining whether or not each module should initialise itself.
On some projects, I have a build script to concatenate these modules within another closure which might look like this:
( function( window ) {
var $ = window.jQuery; //call me paranoid, but I like my vars clean
$(document).ready( function() {
// stuff the modules here, one after another, in any sensible order.
});
}(window);
In other projects, I am able to move the $(document).ready()-Bit into the modules where document.ready is needed, and listening to other Initialisation-Events within others, which feels a bit cleaner for me.
But anyway - having
a build process rather than a lot of single requests
several small, "one-thing-only"-Files to go into the build
a self-enforced "top-level lambda function" due to the intro/outro-Concatenation-Style I adapted from jQuery itself
has significantly improved my DRY-ness and, even, my JS code style.

Function Undefined: Must a javascript function be defined within the same file?

I've got a file notifications.js containing one event bound to an element, and a function updateNotification(). This function uses jQuery to update certain elements on the page when a JSON object is passed as a parameter.
The problem:
I'm attempting to call this function within the page (via <script> tags), however rather than calling it, it breaks the page. I did some digging around within the Chrome Developer Console (not sure of the name), and an error is flagged:
/pleaseshare/views/install/:50 Uncaught ReferenceError:updateNotification is not defined
However, when I pan within the console, I can clearly see the file notifications.js listed under scripts, and the function is defined there. If I define the function within the current scope (e.g. the line above the call), it works fine.
What I've tried
The function contains some javascript that requires jQuery, so I've attempted both with and without encasing it in $(document).ready( function() {});, with neither seeming to have any affect.
I'm pretty stumped.
For good measure, here's a link to show the structure of my javascript and html: http://snippi.com/s/znk6xe9
Any help in figuring out why this is happening, or explanations of why javascript functions cannot be called cross-file (although I'd hope this isn't the case), would be greatly appreciated ;)!!
A function cannot be called unless it was defined in the same file or one loaded before the attempt to call it.
A function cannot be called unless it is in the same or greater scope then the one trying to call it.
You code looks like the structure should work, but is clearly a reduced test case that has been reduced to the point where it won't.
Got it working. The issue was definitely multi-faceted, but I figured it out.
First off the use of RequireJS had an impact on updateNotification(), in that it couldn't be called cross-file, and was therefore considered undefined. I assume this because of how RequireJS loads files, and I'll look into the documentation later (and post an edit if I find anything relevant).
Secondly, updateNotification() would again be considered undefined when encased within jQuery's DOM ready loader $(document).ready(function(){}). However updateNotification() contains executions which require jQuery, so I had to encase the contents of the function in $(document).ready(function(){}).
This is an issue very unique to RequireJS/jQuery, hence why in most use cases this wouldn't occur.
Side note: The tags are edited to reflect this.
you need to import your script into your page:
<script type="text/javascript" language="javascript" src="path/to/notifications.js"></script>
This needs to be added above the <script> tag that calls updateNotification()
Functions do not need to be declared in the same file. In fact, avoiding having every declaration dumped into the global namespace is usually a concern in JavaScript.
In the sample code in the link you provided, updateNotification is declared as a global, so there should not be a scoping problem.
However, in the same sample, you don't show notifications.js being included. You need to import it using a <script></script> element and that element must come before the script element that includes the call to updateNotification. You also must include jQuery before notifications.js, since it uses jQuery. So you need something like:
<body>
// One or two elements
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="notifications.js"></script>
<script type="text/javascript">
$(document).ready( function() {
var json = {status : 'ok', message: 'Hello'};
updateNotification(json);
});
</script>
// All other elements
</body>

Google Website Optimiser Control Javascript

Could someone explain the javascript that makes up Google's Website Optimiser Control script? Specifically: the first two lines, which seem to be empty functions, and why is the third function wrapped parentheses () ?
As far as I can tell this script is basically writing out a new <script> which presumably loads something for A/B testing.
function utmx_section(){}
function utmx(){}
(function() {
var k='0634742331',d=document,l=d.location,c=d.cookie;
function f(n) {
if(c) {
var i=c.indexOf(n+'=');
if (i>-1) {
var j=c.indexOf(';',i);
return escape(c.substring(i+n.length+1,j<0?c.length:j))
}
}
}
var x=f('__utmx'),xx=f('__utmxx'),h=l.hash;
d.write('<sc'+'ript src="'+'http'+(l.protocol=='https:'?'s://ssl':'://www')+'.google-analytics.com'+'/siteopt.js?v=1&utmxkey='+k+'&utmx='+(x?x:'')+'&utmxx='+(xx?xx:'')+'&utmxtime='+new Date().valueOf()+(h?'&utmxhash='+escape(h.substr(1)):'')+'" type="text/javascript" charset="utf-8"></sc'+'ript>')
}
)();
I've attempted to step through with the firebug debugger but it doesn't seem to like it. Any insights much appreciated.
Many thanks
inside anonymous function it shortens names of document and cookies inside it at first, function f(n) gets value of cookie under name n. Then Google reads its cookies and with help of d.write it loads its scripts (as I see they are related to Google Analytic). This way it makes On-Demand JavaScript loading... Actually you load these scripts all the time, Google just needs some additional parameters in url, so this is done this way - save parameters in cookie, which next time are used to get script again.
And finally back to the first two magic lines :) After Google loads its script (after executing d.write), there are some functions which uses utmx and utmx_section, as well as definition of these functions, or better to say overriding. I think they are empty at first just because another function can execute it before its real definition, and having empty functions nothing will happen (and no JS error), otherwise script would not work. E.g. after first iteration there is some data, which is used to make real definition of these functions and everything starts to work :)
The first 2 functions are in fact empty, and are probably overridden later on.
The third function is an anonymous self-executing function. The brackets are a convention to make you aware of the fact that it is self executing.
the "f" function looks up the value given to it in the document's cookies and returns it. Then a new script tag is written to document (and requested from server) with these values as part of its URL.

Categories

Resources