On my page I initially declare variable var as which creates an object through plugin using createAll... I'm referring to this plugin: http://kolber.github.io/audiojs/docs/
In order for plugin to work this object needs to be created. So after that I load some contact through ajax and plugin needs to be applied to this new content, so again I create this var as to create object, however now there are two similar objects on a page which conflict. I would like to know it there is a way where I can make var as that gets created after ajax call equal to existing object on a page?
I tried looking at what's inside var as by doing alert(as); This returns [Object object]
EDIT
This is what gets printed out with console log (This is original, first object)
Object
duration: 1
element: HTMLAudioElement
loadStartedCalled: false
loadedPercent: 0
mp3: null
playing: false
settings: Object
source: HTMLAudioElement
wrapper: HTMLDivElement
__proto__: Object
This is how objects are created, but I believe you need to know the plugin well to understand this
// Initialize audio js
audiojs.events.ready(function() {
var as = audiojs.createAll({
});
});
I've tested a working solution. Please note, the code is just to show it works - see my explanation below for specifics.
var as;
audiojs.events.ready(function () {
as = audiojs.createAll();
});
$(document).ready(function () {
setTimeout(function () {
var mp3 = "http://s3.amazonaws.com/audiojs/02-juicy-r.mp3"; // audio.js example
// creating new audio element, yours is probably added via ajax
// [0] used to get DOM element instead of jQuery object.
var audio = $('<audio/>', {id: 'test'}).appendTo('body').attr('src', mp3)[0];
var testAS = audiojs.create(audio); // initialise new audio.js player
as.push(testAS); // add "testAS" object to "as" array of objects
console.log(as); // log "as" - now holds the original objects + "testAS"
}, 5000); // timeout used for testing, above code can be in ajax success function instead
});
The mp3 and audio variables are just used as a demonstration as I don't know your ajax function's structure.
Audio.js has a .create() function which takes a single element as it's argument and returns an object. The original as variable is an array containing all the audio objects so you can just push the new object onto the end.
By defining as outside a function you make it global meaning that everything can access it and any new audio.js objects can be appended.
Related
I need to add an overlay to an existing OpenSeadragon viewer object which isn't created by my code, but elsewhere in the application.
I have got to a point where I know that the viewer has been created as I can access the various html elements that are created via jQuery. However I can't work out if there's any way to create a viewer from an existing reference.
I've tried using the id of the viewer div in:
var viewer = OpenSeadragon(id: "open-seadragon-viewer-id");
but this doesn't seem to work.
Is there any way to do this or can you only get the viewer within the code that initialised it?
Here's one crazy thought... you could monkey-patch some portion of OSD in order to grab the viewer...
var viewer;
var originalIsOpen = OpenSeadragon.Viewer.prototype.isOpen;
OpenSeadragon.Viewer.prototype.isOpen = function() {
// Now we know the viewer!
viewer = this;
// Reinstate the original, since we only need to run our version once
OpenSeadragon.Viewer.prototype.isOpen = originalIsOpen;
// Call the original
return originalIsOpen.call(this);
}
It's kind of tacky, but should work. Note this assumes there is only one viewer on the page... if there are more than one, the same principle could work but you would need to keep track of an array of viewers.
BTW, I'm using isOpen, because it's simple and it gets called every frame. Other functions could work as well.
EDIT: fixed code so we are using the prototype. I still haven't actually tested this code so there may still be bugs!
This solution does not directly answer the question, as it relies on your own code creating the OpenSeaDragon object. It is an implementation of #iangilman's mention of storing the viewer in a global variable. However others may find it useful. (Note that passing a global variable to a function requires a workaround - see Passing a global variable to a function)
The code demonstrates how to use the same OpenSeaDragon object to display different pictures.
var viewer3=null; //global variable
var newURL1='image/imageToDisplay1.png';
var newURL2='image/imageToDisplay2.png';
var elementID='myID';
//the loadScan function will display the picture using openSeaDragon and can be called as many times as you want.
loadScan("viewer3",newURL1,elementID);
loadScan("viewer3",newURL2,elementID);
//the actual function
function loadScan(theViewer,newURL,theID) {
//if object has already been created, then just change the image
if (window[theViewer]!=null) {
window[theViewer].open({
type: 'image',
url: newURL
});
} else {
//create a new OpenSeadragon object
window[theViewer] = OpenSeadragon({
prefixUrl: "/myapp/vendor/openseadragon/images/",
id: theID,
defaultZoomLevel: 1,
tileSources: {
url: newURL,
type: 'image'
}
});
}
}
I'm using Mongoose for MongoDB operations in my project. I'm trying to:
find every document matching query
create a new object (let's call it objects)
for every document found create a new object inside objects
save fields from found document to created object
And this works just fine. But I also want to:
for every object saved inside my objects find one document matching query in another collection
if document is found, save fields from it to previously created object objects (as new keys)
My code for the second part looks like this:
for(var i in objects) {
if(objects.hasOwnProperty(i)) {
Model.findOne({name: objects[i].name, id: objects[i].id}, function(e, document) {
if(e) console.error(e);
if(document) {
console.log("Found matchind document"); //This is showed for each object, as expected.
objects[i].newField = document.someData;
objects[i].evenNewerField = document.someMoreData;
}
});
}
}
console.log(objects); //This shows old data from previous operations, no new data from the for loop
Your problem is not your mongoose usage, you should take a deep look to Javascript scope and asynchronous. In your code when console.log is called, objects is not yet updated.
I'm trying to write a plugin-like function in jQuery to add elements to a container with AJAX.
It looks like this:
$.fn.cacheload = function(index) {
var $this = $(this);
$.get("cache.php", {{ id: index }).done(function(data) {
// cache.php returns <div class='entry'>Content</div> ...
$(data).insertAfter($this.last());
});
}
and I would like to use it like this:
var entries = $("div.entry"),
id = 28;
entries.cacheload(id);
Think that this would load another "entry"-container and add it to the DOM.
This is works so far. But of course the variable that holds the cached jQuery object (entries) isn't updated. So if there were two divs in the beginning and you would add another with this function it would show in the DOM, but entries would still reference the original two divs only.
I know you can't use the return value of get because the AJAX-call is asynchronous. But is there any way to update the cached object so it contains the elements loaded via AJAX as well?
I know I could do it like this and re-query after inserting:
$.get("cache.php", {{ id: num }).done(function(data) {
$(data).insertAfter($this.last());
entries = $("div.entry");
});
but for this I would have to reference the variable holding the cached objects directly.
Is there any way around this so the function is self-contained?
I tried re-assigning $(this), but got an error. .add() doesn't update the cached object, it creates a new (temporary) object.
Thanks a lot!
// UPDATE:
John S gave a really good answer below. However, I ended up realizing that for me something else would actually work better.
Now the plugin function inserts a blank element (synchronously) and when the AJAX call is complete the attributes of that element are updated. That also ensures that elements are loaded in the correct order. For anyone stumbling over this, here is a JSFiddle: http://jsfiddle.net/JZsLt/2/
As you said yourself, the ajax call is asynchronous. Therefore, your plugin is asynchronous as as well. There's no way for your plugin to add the new elements to the jQuery object until the ajax call returns. Plus, as you discovered, you can't really add to the original jQuery object, you can only create a new jQuery object.
What you can do is have the plugin take a callback function as a second parameter. The callback could be passed a jQuery object that contains the original elements plus the newly inserted ones.
$.fn.cacheload = function(index, callback) {
var $this = this;
$.get('cache.php', { id: index }).done(function(html) {
var $elements = $(html);
$this.last().after($elements);
if (callback) {
callback.call($this, $this.add($elements));
}
});
return $this;
};
Then you could call:
entries.cacheload(id, function($newEntries) { doSomething($newEntries); } );
Of course, you could do this:
entries.cacheload(id, function($newEntries) { entries = $newEntries; } );
But entries will not be changed until the ajax call returns, so I don't see much value in it.
BTW: this inside a plugin refers to a jQuery object, so there's no need to call $(this).
I'm trying to use the Ajax File Upload as featured here: http://valums.com/ajax-upload/
As you can see, I need to create a qq.FileUploader object to initialize the script. However, I need to be able to dynamically create this objects without knowing the IDs of the elements. I've tried creating something like this:
var uploader, i = 0;
$(".file-upload").each(function() {
$e = $(this);
i++;
uploader[i] = new qq.FileUploader({
element: $(this)[0],
action: 'uploadfile.php',
allowedExtensions: ['doc', 'docx', 'pdf'],
multiple: false,
onComplete: function(id, fileName, responseJSON) {
$($e).siblings('input').val(responseJSON.newfilename);
}
});
});
I've learned that the [i] part I have added breaks the script, because I cannot have objects inside of an array.
Is there another way I can create this objects dynamically? They need to all have a unique name, otherwise the onComplete function gets overwritten for all of them. I experimented with using eval(), but I can't seem to make it work correctly.
You have to declare uploader as an array first :
var uploader = [];
Because you declared the variable without defining it, it has the default value of undefined , and your code was translated into something like undefined[i] which triggers an error.
Has to be something like
var uploader = {};
or else uploader is null and you cannot assign anything to it.
EDIT:
So there're two opitions, in my opinion, if one wants to have an array than it makes sense to declare one, var uploader = []; and then use the uploader.push() method or define it as an object var uploader = {}; and just do uploader[i] = ....
It is also possible to do the latter with an a array, but in the latter case I see no point in maintaining the counter (i).
I am working on a Javascript object that contains some YUI objects. The key thing is, my object needs to contain it's own set of YUI tabs so that I can display multiple instances of my object on the same page and have the tabs control their own object instance.
I set it up as follows:
var Scheduler = function(divid,startDate,mode){
this.tabView = null;
...
this.init = function(){
this.tabView.appendTo(this.calendar_cell);
this.tabView.addTab( new YAHOO.widget.Tab({
label: 'Day',
content:'<div id="'+ this.calendar_day_div +'" style="width:100%; height:auto;"></div>'
}));
var tab0 = this.tabView.getTab(0);
tab0.addListener('click', this.showWeek);
}
this.showWeek(){
alert(this);
}
});
Here's the problem. I would expect the alert(this); in this.showWeek to alert the instance of scheduler. Instead, it's giving me the tab li. I tried alerting this.parent and am given 'undefined' as an answer.
How should I set this up to do what I need to do?
The addListenter method takes a scope argument. So you can change your call to the following to solve your problem (since you are using YUI):
tab0.addListener('click', this.showWeek, undefined, this);
When you attach a function to an event of an object (in this case the object held by tab0) then its usually that object that becomes the this context of the function when it executes.
Adjust your code like this:-
var self = this;
this.showWeek(){
alert(self);
}