I am working on a site, where I sometimes need to load a big banner into my header. The header has some default styles, which I need to remove if the specific page has a banner. These extra styles are in a class, which is then removed server side if there is a banner present. It works across all browsers, except in IE9.
document.onreadystatechange = function () {
// Initialize app when document is "ready"
if (document.readyState == "complete") {
var dom = {};
dom.$header = document.querySelector('.js-header');
dom.$banner = document.querySelector('.js-banner-image');
resizeBanner();
}
}
function resizeBanner(){
if(dom.$banner && dom.$banner !== null && dom.$banner !== undefined) {
dom.$header.classList.remove('has-no-banner');
}
}
The browser halts when it tries to remove the class, because it is "unable to get property 'remove' of undefined or null reference". However, the variable is defined and the element exists in the DOM.
If I go to a page that doesn't have a banner, the function doesn't fire (this is expected behaviour), so logically it's not the conditional that's messed up, it finds dom.$banner just fine, but just to test I've tried giving the element an ID, and declare that right before my method. That did not solve the problem.
The script file is referenced in the bottom of my document with defer async.
What am I doing wrong here?
The .classList property is not supported in IE9. Use a more traditional way of adding/removing classes as shown here: Adding and Deleting from objects in javascript
Related
I am trying to append a web component DOM node comp with a property myprop inside an iframe.
const frame = document.createElement('iframe')
frame.src = 'about:blank'
frame.addEventListener('load', _ => {
console.log(comp.myprop) // "abc"
frame.contentDocument.body.appendChild(comp)
console.log(comp.myprop) // undefined in Firefox, "abc" in Chrome, Safari
})
This works perfectly in Chrome and Safari. However, Firefox seems to delete myprop after comp is appended to the body of the iframe.
Chrome and Firefox don't have the same interpretation of the Custom Element definition scope.
With Chrome, when you move a custom element from the main document to an inner <iframe>, it remains a (defined) custom element with all its methods and properties.
With Firefox, when you move a custom element from the main document to an inner <iframe>, because of frame isoation, the custom element is undefined in the context of the Frame, the element is an unknown tag with no custom property or custom method.
You could try to store the value of comp.myprop in some different variable and re-assign it on comp after adding comp to the iframe. Something like this:
frame.addEventListener('load', _ => {
console.log(comp.myprop);
var propStorage = comp.myprop;
frame.contentDocument.body.appendChild(comp);
//You might need to add if(comp.myprop === undefined) here
comp.myprop = propStorage;
console.log(comp.myprop);
})
Firefox is broken, (in more than just this way, in case you wondered why their market share is a shadow of it's former self), but you can work around this particular problem by restoring the prototype in the adoptedCallback of the class definition.
adoptedCallback()
{
Object.setPrototypeOf(this,savedConstructor.prototype);
}
You can't use the generic this.constructor.prototype as it's been reset, so you have to use an explicit reference to the prototype.
After several years of using Jquery I have decided to learn at least basic Javascript. I have run into what is to me a strange problem.
If I have a script like this that runs on page 1, but do not have the same class's on page 2, all scripts stop running that come after this script.
var numberOfClasses = document.querySelectorAll("li.line");
document.querySelector("p.classes").innerHTML = 'Number of support Links ' + numberOfClasses.length;
If I do not have the "p.classes" on the second page, nothing in the JavaScript file that comes after code that will run. Is this normal? The code is in a JS file that is included at the bottom of the html file on both pages. The code above is for example only
The error message on the second page is TypeError: document.getElementById(...) is null, which refers to the first bit of code in the JS file that is not present on the 2nd page
Thanks for your time
jQuery silently "fails" for these situations. If it doesn't find a selector it just returns an empty jQuery object that you can still call methods from, though they wont do anything.
Example
jQuery('NonExistentElement').html("won't show up")
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
No error will be thrown.
Native DOM methods like querySelector() don't return an empty object that you can still access methods from. They will either return the element, a list of elements (NodeList,HTMLCollection, etc) or null. Thus if you try to access a property on a return value from one of these you have a potential for failure in the case of a null return
document.querySelector('NonExistentElement').innerHTML = "Won't show up";
This is why you need to check for null before trying to use it
var element = document.querySelector('p.classes');
if(element != null){
element.innerHTML = "your html";
}
var element2 = document.querySelector('p.classes2');
if(element2 != null){
element2.innerHTML = "no error as the if statement fails and so this code wont execute";
}
<p class="classes"></p>
I have below code which is defined inside a function which actually set width of parent component and do layout...this function is called from 4 places and at one place there is scenario that below error comes, you can see i have checked for undefined but still it is going inside this IF and i get error :( please help identify issue
Ext Js 3.4.2
ERROR
Uncaught TypeError: Cannot read property 'getWidth' of undefined
CODE
if((typeof Ext.getCmp("cmp1") !== 'undefined') && (typeof Ext.getCmp("cmp2") !== 'undefined')){
Ext.getCmp("cmp1").setWidth(Ext.getCmp("cmp2").getWidth()-2);
Ext.getCmp("cmp1").doLayout();
}else{
//Call self again in 3 sec once render
//setTimeout("doLayoutofcustomPanel()", 3000);
}
I able to figure out issue actually component was created but element (EL) was not present initially so it able to cross my IF check I need to put check as below to ensure element is present for which I need to fetch width. This worked fine
typeof Ext.getCmp("cmp2").el !== 'undefined'
I am using ExtJs 3.4.2
Not sure which version of ExtJs you are using, but its better to use itemId
itemId is scoped locally to the container -- avoiding potential
conflicts with Ext.ComponentManager which requires a unique id
and then query to get it.
I have a Strange issue with the latest Mozilla Browser 13.0 with Ubuntu. The code works perfectly in other browsers and also previous versions of mozilla.
Here is the Code
$(document).click(function(event) {
var target = $(event.target);
if (!target.attr('class').match(/^RefineClick/) && target.parents('.RefineClick').length == 0) {
jQuery('.RefineClick').fadeOut();
}
});
And iam getting the following Error :
Target.attr('class').... is undefined
Here is the Screenshot for that: http://i47.tinypic.com/dqoits.png
Well... working for me?
http://jsfiddle.net/acrashik/b9MCj/
If there is no class attached to the clicked element target.attr('class') returns undefined (since v1.6); in FF that's expressed as the error you see when you attempt to call .match. (In chrome it would be "can't call method match of undefined")
Add a check for an absent class; if (typeof target.attr('class') === "undefined") return;
You are binding that function to a 'click' event on the entire document. Therefore any click would trigger the handler, including those on elements without a class attribute set. While this would work fine if you tested it only on elements with a defined 'class' attribute (in any browser) it would throw the error (in any browser) because you try and call the method .match() on an undefined value.
"As of jQuery 1.6, the .attr() method returns undefined for attributes that have not been set." API ref.
Since you are using jQuery, who not use it's full capabilities? It has a built in .hasClass() method:
$(document).click(function(event) {
var target = $(event.target);
if (!target.hasClass('RefineClick') && target.parents('.RefineClick').length == 0) {
$('.RefineClick').fadeOut();
}
});
Note that the input to that method is the class-name rather than a class selector.
My Firefox extension grabs a jQuery 1.4.2 object that is already embedded on a webpage and then tries to use that jQuery object to modify that page. It worked well in Firefox 3.x, but it does not seem to work in Firefox 4.
Here's my code:
window.addEventListener("load", function() { MyExt.init(); }, false);
var MyExt = {
targetHost: "somewebsite.com",
init: function() {
var appcontent = document.getElementById("appcontent"); // browser
if (appcontent){
appcontent.addEventListener("DOMContentLoaded", MyExt.onPageLoad, true);
}
},
onPageLoad: function(aEvent) {
var doc = aEvent.originalTarget; // doc is document that triggered "onload" event
var loc = doc.location;
var host = '';
if (loc.toString() != "about:blank") {
host = doc.location.host;
}
// Edit page
if (host == MyExt.targetHost) {
var $ = doc.defaultView.wrappedJSObject.$;
// this works
$('p').css('color', 'green');
// this works in Firefox 3.x, but does not work in Firefox 4
// instead it shows the following error:
// "Error: uncaught exception: TypeError: handler is undefined"
$('.sometextarea').keyup(function(event) { alert('it should work, but does not'); });
// even this does not work as expected
// it should display true, but it displays false
alert($.isFunction(function(){}));
}
}
What am I doing wrong?
Yes, you have to use wrappedJSObject due to API changes:
Specifying xpcnativewrappers=no in your manifest (that is, XPCNativeWrapper automation) is no longer supported. This was always intended to be a short-term workaround to allow extensions to continue to work while their authors updated their code to use XPCNativeWrappers.
If your add-on depends upon XBL bindings attached to content objects—for example, the ability to call functions or get and set properties created by the XBL binding—you will need to use the XPCNativeWrapper property wrappedJSObject to access wrapped objects.
If you need to be able to call functions or access properties defined by web content, you'll need to do this as well. This may be the case if, for example, you've written an extension that adds a delete button to a web mail service, and the service defines a window.delete() function that you need to call.
If, on the other hand, all you're doing with content is accessing DOM methods and properties, you've never needed to be using xpcnativewrappers=no in the first place, and should simply remove it from your manifest.