I have this code in a Meteor.methods definition:
update_field: function(collection,document_id,field,value) {
obj = {};
obj[field] = value;
console.log(obj);
if (collection == 'clients') {
var Collection = Clients;
} else if(collection = 'sites') {
var Collection = Sites;
}
Collection.update(
{
_id: document_id
}, {
$set: obj
}, function(error,id) {
console.log(error,id);
return(error,id);
}
);
}
This method is called from several client-side helpers events, and updates the field as needed. But whenever it runs once, it never stops running. Sometimes it runs infinitely even when all the Meteor.call('update_field')s have been commented out. I have tried including a 'caller' parameter and adding that to all the possible calls to figure out why it keeps getting called to no avail. Any ideas why this is looping?
Edit: this runs 2,000/minute
Edit2: this is called in one of two ways: on a keyup code==13 (enter) in an appropriate field or a field blur. However, event when these calls are commented out, the issue persists.
Especially your second comment worries me:
However, even when these calls are commented out, the issue persists.
Then who is calling it? The behaviour you're describing points to some helper executing the method. The method changes some data, which re-executes the helper (reactivity) and we end up with a classic endless loop.
Check your entire source code for references to this method:
$ grep -r "update_field" *
Maybe you set a variable somehow and then use the variable to call the method. Also: Have you declared the method inside a Meteor.methods({ ... }) block?
I think the issue was that one of my methods blurred the input field but preventDefaulted. Then the blur handler was called and caused the loop from there. This is my first Meteor project, so I'm chalking this one up to not quite understanding the system sufficiently. I still find it strange that the method was getting called when the callers were commented out, but I'll figure that one out another day.
Related
// page load
InitTeacherLinks()
function InitTeacherLinks()
{
$(".open-ungraded-test").click(function()
{
$.post("class_viewer.php", {
_open_lesson_direct : 1
}, function(data)
{
$("#content_display").html(data);
InitGradingActions(test_taken_id); // Notice this Call
});
})
}
function InitGradingActions(test_taken_id)
{
$("#save_grading").click(function()
{
$.post("class_viewer.php", {
_save_graded_test : 1
}, function(data)
{
$("#content_display").html(data);
InitTeacherLinks(); // Is this Circular logic?
});
});
}
Basically, I have a div called content_display that shows a list of tests. After I load it full of tests, I have to make each test link clickable. So I do that in this function: InitTeacherLinks() where they can view an individual test.
Well the user can exit the test and go back to the original test list. So I have to call the parent function again in the child function.
While this DOES work, I notice I do it often. Is this bad logic or bad for performance?
Note: I can only think of one possible reason why this may work. Please correct me if I am wrong. when save_grading is clicked, it effectively destroys reference to the original (parent function) so rather than creating a duplicated reference, we are simply reinitialize it. Is this right?
I don't think there's a stack overflow issue with the code, but it does look like there may be an error. Every time InitTeacherLinks() is executed, a new click handler is assigned to .open-ungraded-test. That means there is an additional ajax post made during that click for every time InitTeacherLinks() is run, which could be a lot.
At least that's how it looks from the code. This could depend on the structure of your document.
I ended up not changing anything and went with what I have above.
Because the click events are unbinded every time the element is destroyed, this was not creating an endless loop (or Stackoverflow error) which was my concern. The code in the question is correct.
I'm displaying a series of images in a loop, and I'm trying to implement some sort of nudity filter so I'm using nude.js, a library that can somewhat detect nudity. Here's the code:
// we're inside a loop
$(".images").prepend($("<img>").attr({src: whatever, id: uniqueid}).load(function(e) {
nude.load(e.target.id);
nude.scan(function(result) { if (!result) $(e.target).detach(); });
});
However, it detaches all of the wrong images because nude.js is slow and it completes after the loop has gone on to the later iterations, detaching those images instead of the one it was working on.
I've tried using a function factory:
function generateCallback(arg) {
return function(result) { if (!result) $(arg).detach(); };
}
and
nude.scan( generateCallback(e.target) )
but the same thing happens.
What I want is a load event that will remove the image if it seems to contain nudity. How can I do this properly?
EDIT: nude.js works like this:
nude.load(imageid);
nude.scan(callback); // it'll pass true or false into the callback
another edit: accidentally omitted the id setting from the code I posted, but it was there in my real code, so I added it here.
I suspect the case here is that this kind of sequential processing won't work with nude.js.
Looking at the nude.js code, I think your problem is occurring in the call to nude.scan. nude.js has a variable that stores the function to invoke after the scan has completed. When calling nude.scan(callback), this variable is set to be callback.
From your PasteBin, it seems as though the callback gets assigned as expected on the first call, but on the second and subsequent calls, it gets replaced, hence why the second image is detached and not the first.
What happends to your script, is that the e var is global to the function and so after each loop it gets replaced with the new one. So when the first image is scanned, e already became the event of the second image, which get detached.
To solve your problem, use closures. If you want to know more about closures, have a look here.
Otherway, here's the solution to your problem :
$(".images").prepend($("<img>").attr({src: whatever, id: uniqueid}).load(function(e) {
(function(e) {
nude.load(e.target.id);
nude.scan(function(result) { if (!result) $(e.target).detach(); });
}) (e);
});
EDIT: AS nick_w said, there is var that contains the callback and probably gets replaced each time so this is why it isn't the right picture getting detached. You will probably have to modify the script yourself
I'm attempting to get the length of the array of a simple angularFireCollection and can't seem to:
var stf = new FireBase("http://myfirebase-app.firebaseio.com/staff");
function staffListCtrl($scope, angularFireCollection){
$scope.staff = angularFireCollection(stf);
console.log($scope.staff.length);
}
The output in the console says:
0
Which I know is incorrect. It should be returning somewhere around 5 as the length (see screenshot below for the output of $scope.staff.
Any help is a appreciated as I can't seem to get past this absolutely, utterly simple JS task.
In this case, the correct way to print the number of retrieved elements within the callback would be following:
var stf = new FireBase("http://myfirebase-app.firebaseio.com/staff");
function staffListCtrl($scope, angularFireCollection) {
$scope.staff = angularFireCollection(stf, function() {
console.log(stf.numChildren());
});
}
The reason for this is that the initial callback function is called before actual assignment to $scope.staff takes place. So within the callback function you can access only the Firebase DataSnapshot object stf. Hope this helps.
You're trying to access the length immediately after calling angularFireCollection, but the actual data is retrieved over the network and therefore it takes a little while for the array to be updated. You can pass a function as an argument to angularFireCollection to be notified about when the initial data is loaded, like so:
var stf = new FireBase("http://myfirebase-app.firebaseio.com/staff");
function staffListCtrl($scope, angularFireCollection) {
$scope.staff = angularFireCollection(stf, function() {
console.log($scope.staff.length);
});
}
ah, I see it in angularfire.js. Line 298 wraps adding an item in a $timeout. That's causing the initalCb() to get called before the data has been added to the collection. I pulled the $timeout and it worked. However, then I had to call $scope.$apply() to reflect the added items. I ended up passing scope into angularFireCollection to be sure $apply() gets called. No idea what else I broke by pulling the timeout.
this is a view of the issue: plunkr
EDIT:
as far as I can tell and showed in the plunkr, this doesn't work.
$scope.staff = angularFireCollection(stf, function() {
console.log($scope.staff.length);
});
and while pulling the $timeout from angularfire.js did fix that particular issue, it caused all kinds of other headaches with databinding(as expected), so I put it back. It seems the way to go is to use the snapshot that is passed in the callback. I can't find a lot of documentation on it, but here's what worked for me:
$scope.staff = angularFireCollection(stf, function(snapshot) {
angular.forEach(snapshot, function(item){
//will let you iterate through the data in the snapshot
});
});
I'm developing a small plugin that changes the favicons if there are unread messages in mailbox in Roundcubemail. However, the API sucks, and the event listupdate is fired only when the whole page is loaded, even if it is meant to fire when the list is updated.
However, I've managed to find out, that every time the list is updated, certain functions are called, such as set_unread_count. It gets the unread-count easily, so it would be great to somehow "append" stuff to this function. I just think based on hours of searching that there is no solution for this. Can I add a callback to be called when the set_unread_count is called? Can I somehow append stuff to that function? Any other ideas?
Create a little hook.
var _old_set_unread_count = set_unread_count;
set_unread_count = function() {
// do whatever you want here
// access arguments[x] to get arguments.
_old_set_unread_count.apply(this, arguments);
};
Demo: http://www.jsfiddle.net/4yUqL/69/
Is there a way to include a javascript file only once or declare a function only once? The issue I am having is that I have an HTML module that contains a javascript include. Well this module is loaded in a loop, and therefore that file is loaded multiple times. I've worked out most of the kinks, but what bothers me is that I know the same function is getting created multiple times, and this look can be as many as 30 iterations. To me, I don't like the fact that the same function is getting created over and over. Should I care? Is there a way I can prevent this? I know I can detect when a function exists, can I put the function declaration in between an if statement?
Update
I've tried out one of the suggestions:
if(typeof btnSendInvite_click != 'function')
{
function btnSendInvite_click()
{
alert("#invite_guest_" + $(this).attr("event_id"));
return false;
}
}
but that doesn't work. I've also tried
if(!btnSendInvite_click)
{
function btnSendInvite_click()
{
alert("#invite_guest_" + $(this).attr("event_id"));
return false;
}
}
but it doesn't work. What happens is that I have this line:
$(document).ready(function()
{
$(".btnSendInvite").bind("click", btnSendInvite_click);
});
and when the button gets clicked, that functions is executed six times, which is the amount of times that the file was included which tells me that the function is being created multiple times... I think.
Update
So after a lot of struggling, this problem is turning into something different than what I thought. The bind is being called multiple times, so it's getting bound multiple times, and therefore calling the function multiple times. I guess my next question is, is there a way to bind a function to a control only once? I've tried the jquery "one" already and it doesn't work.
Yes, you can (run on jsfiddle).
if (!window.myFunction) {
window.myFunction = function() {
//...
}
}
Edit: In your case it would be:
if (!window.btnSendInvite_click) {
window.btnSendInvite_click = function() {
alert("#invite_guest_" + $(this).attr("event_id"));
return false;
}
}
The call to bind() also has to be somewhere in that conditional block.
Note: The following variant won't work, at least not on all browsers:
if (!window.myFunction) {
function myFunction() {
//...
}
}
Edit 2: For your update:
Declare a variable when you call bind.
if (window.iBoundThatStuff!=true) {
iBoundThatStuff=true;
//call bind() here
}
Having JS included in a loop is ridiculous. Move your JS out of the loop.
JS can tell if function was defined but fixing bad server side loop in JS is definitively a bad practice.
Yes you should worry about not including your script file several times and not to declare the function several times...
For the first part, you may want to look into changing your html structure so the js file is only included once (even though js files are cached by the browser, and the second time may not actually go to the server -- depending of several factors... there's still a penalty)
Now as for declaring your function only once, remember that functions are also object (1st class citizens) in js, so you can test if a function is already define as if you were testing an object.... if(!window.myFunc) { window.myFunc = function(){} }...
You may want to look a bit into functions and scoping in js.. here are some links
http://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/
http://www.yuiblog.com/blog/2010/02/24/video-crockonjs-3/
http://www.slideshare.net/douglascrockford/crockford-on-javascript-act-iii-function-the-ultimate