Overriding appendChild() - javascript

I am trying to override appendChild method so that I can have control over dynamically created elements and modify them if needed before inserting into the page. I tried with this example code, just to see if it could be done:
var f = Element.prototype.appendChild;
Element.prototype.appendChild = function(){f.apply(this, arguments); };
and it works for simple examples.However, when I try to load jquery after this code:
<script>
var f = Element.prototype.appendChild;
Element.prototype.appendChild = function(){f.apply(this, arguments); };
</script>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>
I get this errors:
Uncaught TypeError: Cannot read property 'selected' of undefined jquery.min.js:4
Uncaught TypeError: Cannot read property 'appendChild' of undefined
So, why it doesn't work with jquery ? Is there a safe way to override appendChild ?

It is ill advised to overwrite native functions, but if you do it than make sure you return the appended element as well to prevent problems with code that uses the returned value of the native "appendChild" function:
window.callbackFunc = function(elem, args) {
// write some logic here
}
window.f = Element.prototype.appendChild;
Element.prototype.appendChild = function() {
window.callbackFunc.call(this, arguments);
return window.f.apply(this, arguments);
};

Related

Getting currentScript is returning typeError

I'm trying to get a custom attribute that I put on my script tag:
<script type="text/javascript" src="https://.../mysource.js" customdata="some_value"></script>
I'm using the following code so it will work on IE:
document.currentScript =
document.currentScript ||
(function () {
const field = document.getElementsByTagName('script');
return field[field.length - 1];
})();
// document.currentScript.getAttribute('customdata');
But then I'm receving the following error when I try to set a new value on document.currentScript.
Uncaught TypeError: Cannot set property currentScript of # < Document > which has only a getter
I only solve this when I'm using document.currentScript directly, but then I can't use on older browsers.
If document.currentScript exists, it's a read-only property. So only try to set it if it doesn't exist.
if (!document.currentScript) {
document.currentScript = (function() {
const field = document.getElementsByTagName('script');
return field[field.length - 1];
})();
}
I created another variable to hold the value from document and then it worked and no errors is shown.

in class constructor this.button = document.getElementById('button') / Uncaught TypeError: Cannot read property 'addEventListener' of undefined?

I got my webpack bundle with some bunch of code:
class View extends EventEmitter {
constructor() {
super();
this.input = document.getElementById('input');
this.btn = document.getElementById('button');
this.list = document.getElementById('list');
}
addListeners() {
this.btn.addEventListener('click',this.emit('some', this.inputValue));
}
// some other stuff
}
//--------got error : Uncaught TypeError: Cannot read property 'addEventListener' of undefined
but when i'm doing :
addListeners() {
// document.getElementById('button') instead of this.btn everything is good
document.getElementById('button').addEventListener('click',this.emit('some', this.inputValue));
}
When the constructor is called, the DOM was not yet fully created, so this.btn points to nothing. This is why you can't add an event listener to it.
You could try to make sure the DOM is created before you initialize your class, by wrapping your code in window.onload = func_that_wraps_your_use_of_View()
I think the problem is in the context. In your addListeners method, put inside
console.log(this);
to see what context is inside this function. It may be pointing not to what you expect.
Also, to add event listener you do this:
this.btn.addEventListener('click',this.emit);
With your current code you execute function once, you don't add event listener.

Unable to get property 'queryselectorall' of undefined or null reference

I am getting below mentioned error in my jQuery function:
var timer = document.getElementById(id);
var pdays = timer.querySelector('.days');
var phours = timer.querySelector('.hours');
var pminutes = timer.querySelector('.minutes');
var pseconds = timer.querySelector('.seconds');
0x800a138f - JavaScript runtime error: Unable to get property 'querySelector' of undefined or null reference
Please suggest to me where I can find jQuery file for .queryselectorall() method or remove above mentioned error in jQuery code ?
here is a suggestion!
maybe your JavaScript is executing before your page loads so your document.querySelectorAll() code is returning data with undefined or null reference (zero length).
try to wrap with onload()
onload = yourFunction(){
document.querySelectorAll()
}

How can function be defined via "fn" member in Javascript?

I found the following definition
$.fn.flex = function ( options ) {
var p = this.data("flex"),
opts = options || {};
if (p) return p;
this.each(function () {
p = new Flex( this, opts );
$(this).data("flex", p);
});
return opts.api ? p : this;
};
which defines function flex() in original code.
Unfortunately, it stops defining this function in my environment, i.e. function call causes an error that flex is not a function.
What is critical here for flex being a function?
UPDATE
Sorry, actually I didn't modify anything. I just put this javascript https://github.com/jasonenglish/jquery-flex/ into my environment (Liferay) and the code to run script
<script type="text/javascript">
$(function() {
$(".flex").flex();
});
</script>
caused an error. So I replaced $ to jQuery everywhere as I did before and it is still not working.
UPDATE 2
Hmmm. Error occurs in widget.js from Twitter. Says
TypeError: jQuery(...).flex is not a function
If I rename flex to flex1 everywhere, it says "flex1" is not a function.
Sorry, actually I didn't modify anything. I just put this javascript ... into my environment (Liferay) and the code to run script
Because that's a jQuery plug-in, you need to make sure you include that script after jQuery on the page. So
<script src="/path/to/jquery.js"></script>
<script src="/path/to/the-plugin.js"></script>
If you put them in the other order, the first script will fail because it will try to take the value of the jQuery symbol, which doesn't exist yet, throwing a ReferenceError (in both loose and strict mode).
First of all in $.fn.flex $ and fn are jQuery variables. they are not native to JavaScript. $.fn provided by jQuery to attach method/property to jquery object

jQuery animate callback + Backbone: Cannot call method 'remove' of undefined

I'm not a newbie to JavaScript, but often I find its flexible ways (like defining anonymous function as callbacks and their scope) quite confusing. One thing I'm still struggling with are closures and scopes.
Take this example (from a Backbone model):
'handleRemove': function() {
var thisModel = this;
this.view.$el.slideUp(400, function() { thisModel.view.remove(); });
},
After the model is removed/deleted, this will animate its view and finally remove it from the DOM. This works just fine - but initially I tried the following code:
'handleRemove': function() {
var thisModel = this;
this.view.$el.slideUp(400, thisModel.view.remove );
},
Which is basically the same, but without the function() {} wrapper for the remove() call.
Can someone explain why the latter code does not work? I get the following exception/backtrace:
Uncaught TypeError: Cannot call method 'remove' of undefined backbone-min.js:1272
_.extend.remove backbone-min.js:1272
jQuery.speed.opt.complete jquery-1.8.3.js:9154
jQuery.Callbacks.fire jquery-1.8.3.js:974
jQuery.Callbacks.self.fireWith jquery-1.8.3.js:1084
tick jquery-1.8.3.js:8653
jQuery.fx.tick
Thank you!
That's because the context (this) of the callback function changes to the element being animated by jQuery.
var obj = { fn: function() { // Used as below, the following will print:
alert(this === obj); // false
alert(this.tagName); // "DIV"
}};
$('<div>').slideUp(400, obj.fn);
Furthermore, Backbone's view.remove function looks like this (source code):
remove: function() {
this.$el.remove();
this.stopListening();
return this;
},
Because this is not the Backbone view object any more, $el is not defined. Hence you get the "Cannot call method 'remove' of undefined" error.
Another way to avoid the error is to use Underscore's _.bind method:
this.view.$el.slideUp(400, _.bind(thisModel.view.remove, this) );

Categories