Problem with asynchronous database communication - javascript

I'm communicating with sqlite database in firefox extension. First, I used this synchronous code. Then I changed it to this asynchronous code but it ended with error
anchors[i] is undefined, Line 95
This change didn't help.
There seems to be some problem with variable scope.
thank you for help

One problem is that anchors is apparently a node collection as returned by document.anchors. As such it isn't a fixed list, it will change if the document changes. It might happen that an anchor is removed from the document while your database query is running. To prevent an issue like this you can make a copy of the collection:
var anchors = Array.prototype.slice.apply(document.anchors);
This will make anchors a regular array that won't change unexpectedly.
The other issue is that all your closure functions use the same variable i (see https://developer.mozilla.org/en/JavaScript/Guide/Closures for more info). When handleResult executes i will have the value anchors.length because the loop is already finished. To prevent this you need to capture the "current" value of i, e.g. in the object property like this:
statement.executeAsync({
anchorIndex: i,
handleResult: function(aResultSet) {
...
anchors[this.anchorIndex]
...
}

Related

Simple event system using JavaScript (ES5) - JS Custom Event

Instructions:
make this code work without modifying snippet it in any way.
Use only plain old JavaScript and no third-party libraries.
Write new code that enables the code below to work properly.
Hint: Feel free to extend native objects... even though it's typically a bad practice.
// Start with an object, any object
var myObject = {};
// Register an event on your object using
// an `on` method
myObject.on('myEvent', function(data) {
// Log the data passed to the callback
console.log(data);
});
// Trigger the event using a `trigger` method.
// Include some data when you trigger the event.
myObject.trigger('myEvent', {
company: 'ABC Corp',
location: 'WTC Bangalore, IN',
website: 'http://abc.co'
});
// Register a different event
myObject.on('yourEvent', function() {
console.log('yourEvent fired');
});
// Trigger the new event
myObject.trigger('yourEvent');
// Trigger all existing events using a special
// "star" identifier.
myObject.trigger('*');
// Remove one event by name
myObject.off('myEvent');
// Since we've removed the event, this should
// do nothing
myObject.trigger('myEvent');
// Remove all existing events
myObject.off();
// Since we've removed all events, this should
// do nothing
myObject.trigger('*');
Everything else went well. I'm unable to get "arguments" while implementing myObject.trigger("*"); unable to read arguments object / parameters while implementing "*" and hence throw undefined.
My JSFiddle
Disclaimer
I obviously dont know what school you go to or anything, but please don't fool yourself trying to fool your teachers. With a few simple questions they'll know if you understand the material or not, and if you show up with a good answer but no knowledge to back it up, they will know what's up. I'm not accusing you of this, just a friendly word of advice of someone who has had good connections with his teachers after graduating last year ;)
So, how do we do this? Basically, you will have to add some functionality to the prototype of object, at least if you want this to affect all objects made afterwards. You can always create your own class and add the function to that prototype if you only want that class to have this functionality.
We need 3 functions added to the prototype, on, off and trigger of course. On top of that we add one extra property called events, initially an empty object.
You can look at the raw code for all these in the jsfiddle, I will only go through the structure and logic of the code here.
events will hold all the handlers (functions) associated with each event. When adding an event for the first time, we add a eventName property to the events object, the value for this property is initially an empty array.
on will find (or create) the array linked to eventName in events, and push the function into the array (note we do not call the function at this time, we simply store the reference to the function in the array).
off will iterate the array of eventName, and if it finds the same function (note the ===), remove it from the array.
trigger will iterate the array of eventName and call each function. Note that the function is called with the this keyword in the function set to the object, and with the same parameters as the trigger function was called (except eventName, the first parameter, which is filtered out). Yes that means you can pass as many parameters as you want to trigger(), and they will all be passed to each handler.
I won't go into detail what things like splice, slice, ===, arguments and apply do exactly, I'm sure you can find more and better information about that elsewhere on the world wide interwebs.
There's a lot more you can do for this, like making the events object invisible through some nice uses of scoping, but that wasn't part of the question so I didn't bother with that.
If you have any more questions after looking through this, feel free to ask. I also didn't test it extensively so if you find any bugs, let me know.
EDIT: I didn't read through the comments at first, but I now also added support for the '*' wildcard. Basically the functions now check for the wildcard and will iterate all eventNames on the event object when removing or triggering. You can also remove all functions for an event by not giving a function or by giving the same wildcard, but with an eventName.
EDIT2: had some bugs running the teacher's code, realized I forgot to check for hasOwnProperty while iterating. Look that one up, it's very important when working with prototypes!
I now put in the teacher's code in my jsfiddle, to show you that it works :)
jsfiddle with own code
jsfiddle with teacher code
EDIT3 - about the 'undefined' log.
The teacher's code calls .trigger 5 times, and you should see 4 console logs and as far as I can tell, they are all correct.Let me run through each trigger, and the subsequent console logs.
You add a handler to myEvent, which logs the first parameter
You trigger myEvent, with parameter => The parameter (the object), is
logged.
You add a handler to yourEvent, which logs a hardcoded
string.
You trigger yourEvent, no parameter => The hardcoded string is logged'
You trigger * with no parameter, all handlers run => undefined is logged, since no parameters were given, data in myEvent's handler is undefined. The hardcoded string is also logged
You remove the myEvent handler, trigger myEvent and confirm no functions are called
You remove all event handlers, trigger * and confirm no functions are called from any events.
I honestly don't know what you expected to happen on step 5, since you give no parameter, the data is assigned undefined, that's intended behaviour.
If you want to merge the data given in step 2 so it remains on the object, then instruct so in your handler. (for example, iterate all properties of data and add them to this, then log this). Right now you simply pass it data, it gets logged, and then thrown away. You can also add a parameter in step 5, and then all handlers will receive it (including the yourEvent handlers, but that one doesn't assign nor use it).
document.getElementById("myBtn").addEventListener("click", displayDate);

Jquery each inside each affects only the last element

I have problem with nested loops. Please take a look on the fiddle below:
http://jsfiddle.net/7znfmp9o/
I want each section to get parallax effect however something strange is going on here. .each() code is applied only for last element within the loop.
Changing this line:
$bgElm = $(this).find('.swiper-slide-bg, .mk-section-video')
into this:
$bgElm = $('.parallax-true').eq(0).find('.swiper-slide-bg, .mk-section-video')
runs the snippet on desired section, however iteration on .eq(i) doesn't work either, even within closure:
(function(i){ ... })(i);
What am I missing here? Thx for your help
The problem is due to this line:
$bgElm = $(this).find('.swiper-slide-bg'),
You are setting the contents of this internal variable every time the first forEach occurs. When the event is raised the value of this is the last element in the forEach loop. You should move these variables outside of the forEach loop and append elements into it. Then once the event is raised for loop on the elements within this variable.
I put together a VERY crude implementation of what I am proposing. While it works, you should reorganize the data structures and give proper naming to help describe your intentions. For instance, $bgElm is a poor variable choice for a variable describing the set of parallax-ed elements.
http://jsfiddle.net/myqswjnt/

Does Javascript temporary object need reference variable and/or closures?

I need short messages disappearing after preset time. Please see the fiddle here: http://jsfiddle.net/X88F9/1/.
It works well, what I am not sure about is the reference for each created object:
function addObject() {
new SomeObj(Math.random() * 1000 + 300);
}
it is not stored in any variable, can I just leave it as it is ? Or do I need to push them in some array ?
I also found this recommendation to put all in closures: https://stackoverflow.com/a/10246262/2969375, but not sure if necessary in my case and if yes, then how.
My answer to the question is: Javascript does not need a reference to the object to work, as proofed by your fiddle. So the question is more about if you need a reference to the object, to do other stuff with it later on. If you, for instance, would like to give the user the ability to click the temporarily display message and stop it from disappearing, than you can put all that code in a closure and do not need a reference, too. But if you would like to display the very same object again after it was removed from the DOM, than you need to store it in an array, other object, or variable, depending on your needs and ways to find it in a list.

Javascript override problem class xml

Not sure what is the problem , this the second post looking for the answer.. but this time with a with the example .
What i'm doing : I 'm implementing a gallery that is getting a xml, and then build me using some javascript code. the problem i tried to call twice gallery.init like :
$(document).ready(function(){
galleryXML.init({
id: "#gallery1"
});
galleryXML.init({
id: "#gallery"
});
})
I expected to have one in #gallery1 other in #gallery. Can someone tell me what the problem(it only happen when i had the loadXml() , so probably something with asynchronous call not sure )?
I think your problem can be that you are using the same variable _P for (what you expect to be) 2 different instances of the galleryXML.
The _P variable is created and initialized when the javascript code is parsed, because of the () after the var galleryXML = function() {...}.
So I guess your problem is going to be solved if you just put the variable inside the init of galleryXML. You can see the code here: jsfiddle.net/rpNab/3/ (notice that now each li is inside each gallery, instead of both li in the last gallery)
EDIT: And I realize that now with my modification the galleryXML module seems ugly (because it only has one method and no variables), so I made a minor refactoring in order to have more methods inside that class, but the methods now must receive the parameter because the class itself continue to be "static", but the parameters can make it act for different contexts. Hope it helps: jsfiddle.net/rpNab/4/

jQuery "'events' is null or not an object" error, when using empty() or html()

I am getting the following error in IE:
'events' is null or not an object -- jquery-latest.js?d=1848173663, line 113 character 467
I am using jQuery 1.4.2, I'm not in a position to upgrade yet as we are on an older version of jQuery UI and have way too many bugs using anything newer than 1.4.2.
I get following error when I run this bit of code the second time:
$.post("page/view.do?undoCache=" + Math.random(), {
pageId: pId
}, function(xmlContent){
console.log('1');//get this one
$('#reloadCenterDiv').empty();
console.log('2');//don't get this one unless line above is commented out, then will run til next line
$('#reloadCenterDiv').html(xmlContent);
console.log('3');//don't get this
});
I'm pretty sure I'm not doing anything else to #reloadCenterDiv between calls.
Googling around for the error "'events' is null or not an object" I found this:
"Sounds like a reference to an event
handler is still there, when the
handler itself is already gone."
That sounds logical. Any other ideas of why and when this error would occur?
I have found where this is happening, but all clues for me end there.
How do I clean things up so I can call empty() or html() on #reloadCenterDiv again?
Here is the HTML for #reloadCenterDiv:
<div id="reloadCenterDiv" style="border:none; margin: 0; overflow:auto; overflow-y:scroll; height: auto;"></div>
Not sure, but it would seem like jQuery.cache is being overwritten.
Since a DOM element has (when necessary) a serial number that maps to jQuery.cache, when you run a function like .empty(), jQuery assumes the related data exists, looks up the data for that element, and deletes it.
In place of your first log, do this:
console.log(jQuery.cache);
And see what it gives you. I'll bet that something is overwriting it. Perhaps you're loading jQuery twice?
Here's an example that intentionally deletes jQuery.cache. It gives a similar error.
EDIT:
Summary of the comments below. During .empty() (or actually cleanData()) jQuery grabs the expando from all descendant elements in order to delete the associated data.
The issue is that when jQuery does so, it assumes that the data was successfully located. In this case, somehow the data is being disassociated from the element, so retrieving the data using the value of the expando is returning undefined.
Because jQuery doesn't (or didn't in 1.4.2) verify that data was found, its attempt to access the events property on the data is causing an error, because again data is undefined.
Updated versions of jQuery fix it with if ( data && data.events ) {, which verifies that there is some object against which to ask for its events property.
If you can't update your jQuery, you can set the HTML instead:
$("#divid").html("");
This is essentially doing the same thing.

Categories