Handle "is not a function" error in jquery - javascript

I like to display a custom message to user when jquery plugin required is not loaded on page.
For example to use jshowoff plugin (http://ekallevig.com/jshowoff/) its mandatory to include
jquery.jshowoff.min.js
However I would like to put some code to initially check if jquery.jshowff.min.js is already loaded on the page or not.
And if not loaded, display error message saying that required plugin is not available rather than error is browser console as $.jshowoff is not a function.
Could someone advice on how to implement this please ?
Thank you very much for your help.

If you use the plugin via a jQuery object, e.g.:
$(/*...stuff here...*/).somePlugin();
...then you can test whether it's loaded like this:
if (!$.fn.somePlugin) {
// somePlugin is not loaded for some reason
}
If you use it directly from jQuery ($), e.g:
$.somePlugin();
...then you can test for that like this:
if (!$.somePlugin) {
// somePlugin is not loaded for some reason
}

Related

How can I test jQuery code in the browser console?

I want to test if my jQuery code is sound. So I thought I just enter the code in the browser console. I use Mozilla Firefox.
I want to test if I can select ids and that stuff.
But when I enter:
$("#testId")
I get the following error:
Uncaught SyntaxError: private names aren't valid in this context
Are the elements that I want to access private? What does that mean and why is that?
follow these steps to test & practice JQuery in your console:
first, use the browser debugger tool to inspect any element in your browser, view the source code, e.g like classNames and id'
Next, now use the jQuery syntax to select it example $(".className") or $("#ids"),
just type
console.log($("#testId"));
Try something like this
<div id="testId">hi user1664377</div>
then
console.log($("#testId").text()); // you will see "hi user1664377" in console
In case you dont have access to jQuery in console (window/document).
You can add the jQuery script to DOM directly from console by creating and appending the script to body:
let s = document.createElement('script')
s.setAttribute('src','https://code.jquery.com/jquery-3.6.0.min.js')
document.getElementsByTagName('body')[0].appendChild(s)
And now eg get the jQuery version:
console.log(jQuery.fn.jquery)

Conditionally attaching jQuery plugin functions to elements on the site

I want to attach a jQuery plugin function to an element on my site that exists only on one page. Currently, I'm using this conditional to prevent triggering the limiter function and throwing an error when there is no #advertiser_co_desc in view.
jQuery(document).ready(function($) {
var elem = $('#charNum');
if ($('#advertiser_co_desc').length) {
$('#advertiser_co_desc').limiter(180, elem);
}
});
On my website #advertiser_co_desc is present only on one page.
My solution does the job, but my qualm stems from the fact that the jQuery plugin code as well as the plugin function call presented above (they are both in the same file) get fetched by the browser and the condition is continuously evaluated regardless of whether a user ever gets to a page where #advertiser_co_desc exists.
Is the method I'm using optimal, or is there a better way to attach this particular JS only to the page where '#advertiser_co_desc` exists? Naturally, I wan to avoid adding my scripts in the same file with the PHP code.
Or you can wrap the plugin method as,
var _limiter = $.fn.limiter;
$.fn.limiter = function(limit, element) { // provide complete argmuments
if(this.length) {
_limiter.call(limit, element);
}
};
Make sure that plugin is loaded before this statements.
The best and optimal way to check existence of an element by jquery, is $('#advertiser_co_desc').length that you have used already. So no need to change your code.

Firebreath Object in AngularJS

I have tried to include a FireBreath plugin object in an AngularJS view, however when I try to render the view I get this error:
TypeError: Cannot read property 'nodeName' of undefined
I am able to successfully include the object in the view with $compile like this:
$("body").append($compile('<object id="plugin" type="application/x-firebreathplugin" width="0" height="0></object>')($scope));
However, after including the object like this I cannot get my plugin to fire an event in the JS.
Doing something like this:
plugin = document.getElementById('plugin');
console.log(plugin);
Returns
TypeError
In the Chrome console. But I can still do:
plugin.callFunction();
And have a FireBreath method execute. The issue is when I try to get an event to fire in the JS. No matter what I try, I cannot get the event to fire. So this code will never execute:
var addEvent = function(obj, name, func) {
obj.addEventListener(name, func, false);
}
addEvent(document.getElementById('plugin'), 'firebreathEvent', function(data) {
console.log('data ' + data);
});
var plugin = document.getElementById('plugin');
plugin.functionThatTriggersFireBreathEvent();
Does anybody know if it has something to do with accessing the object after calling $compile? I noticed that in regular HTML (before using AngularJS) logging the plugin in the console returns this :
<JSAPI-Auto Javascript Object>
So I am thinking that whatever I am getting with document.getElementById after using $compile is not the same.
What would be easier is is if I could just include the <object> tag in the view.html file and have it display in <body class='ng-view'> but I get the top TypeError, so if anyone has any ideas for that, that would be preferred.
Any help is appreciated. Thanks.
If anyone is interested, because I could not get the event to fire, I followed along to this link:
http://colonelpanic.net/2010/12/firebreath-tips-asynchronous-javascript-calls/
(which I think is your blog #taxilian) to get the data back to the JS.
Plugin Code: Great example in the link.
JS Code:
//attach FireBreath Object to AngularJS View
$("body").append($compile('<object id="plugin" type="application/x-firebreathplugin" width="1" height="1"><param name="onload" value="pluginLoaded"/></object>')($scope));
var callback = function(data) {
//data is an object
console.log(data.resultFromFireBreath);
}
plugin = document.getElementById("plugin");
plugin.getData(callback);
This will have to work for now until someone can figure out how to attach an event to the plugin object after $compile.
I ran into the same problem and was able to make the problem go away by creating a read-only nodeName property in my plugin object. I asked about this in a firebreath forum post and taxilian suggested adding this to JSAPIAuto.cpp, which also worked, so I submitted a pull request with the change.
I once spent about 6 hours trying to make FireBreath plugins work with jquery; it was really educational, but ultimately I determined that it wasn't worth the work.
Long story short is that it's not worth it; particularly since even if you could make it work, it would break on IE9 where FireBreath doesn't support addEventListener (IE never gives it the even info, so it's a little hard to support) and you would need to use attachEvent anyway.

How can I use jQuery 1.5.2+ on a Firefox addon?

At first I made a function that received a parameter and returned jQuery such as:
function getjQuery(window)
{
/*jquery code*/(window);
return window.jQuery;
}
But then I got an email form the review and they told me I have to use jQuery file with the original file name and completely unmodified.
I started to search for an alternative and found this solution, but there is no way it work.
jQuery object is created, but I can't find any elements. $("#id").length is always 0. With the previous method it was always found.
My current code (which doesn't work)
AddonNameSpace.jQueryAux = jQuery;
AddonNameSpace.$ = function(selector,context) {
return // correct window
new AddonNameSpace.jQueryAux.fn.init(selector,context||contentWindow);
};
AddonNameSpace.$.fn =
AddonNameSpace.$.prototype = AddonNameSpace.jQueryAux.fn;
AddonNameSpace.jQuery = AddonNameSpace.$;
The jQuery file is loading on my browser.xul overlay:
<script type="text/javascript" src="chrome://addon/content/bin/jquery-1.5.2.min.js" />
Am I loading in the right place?
How can I use jQuery to modify the content on a page (HTML) with the original jQuery file, is it even possible?
You need pass the e.originalTarget.defaultView on the second parameter on jquery..
If you don't jquery will use window.document, which is the window.document from the xul.
Use
gBrowser.addEventListener("DOMContentLoaded", function (e) {
$("#id", e.originalTarget.defaultView).length
}, true);
instead of
$("#id").length;
And, for avoid conflicts with other extensions don't use script in the xul page, use MozIJSSubScriptLoader.
Components.classes["#mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader)
.loadSubScript("chrome://youraddon/content/jquery-1.5.2.min.js");
If you use this method, you load jquery only when you need, avoiding memory leak.
The preferred way to load it is with mozIJSSubScriptLoader so you don't collide with other's extensions. I'm not sure why you're having problems, I can use jQuery in my addon like $("#id").hide() with no additional code (although from the sidebar, now browser.xul).
Either way, this blog post provides a pretty good guide and even has an example xpi to download.

Detecting if a plugin has been applied

I have an app that loads conversations. Each time a conversation is loaded I need to destroy and re init the file uploader.
Per: https://github.com/blueimp/jQuery-File-Upload/wiki/API
I'm trying:
// First destroy existing instance
$('.upload').fileUpload('destroy');
// Init
$('.upload').fileUploadUI({
........
Problem is on first run I get an error: "Uncaught No FileUpload with namespace "file_upload" assigned to this element"
Any ideas on how I can somehow detect if the plugin has been applied and only then destroy? Thansk
You should be able to detect if the plugin has been applied to an element using the "namespace" (as the plugin refers to it), which is the .data() key the plugin uses.
With the current defaultNamespace being 'file_upload', try:
var upload = $('.upload');
if (upload.data('file_upload'))
upload.fileUpload('destroy');
Instead of just:
$('.upload').fileUpload('destroy');
This will mirror the plugin's own test, which you can see around line 920 of the current source.

Categories