Missing angular scope when debugging - javascript

I have controller in which i have such broadcast:
$scope.seachColumn= function () {
$scope.$broadcast('seachColumn', true);
}
Other controller which listens for the broadcast:
$scope.$on('seachColumn', function (event) {
//console.log($scope);
console.log('vuala');
});
I comment line console.log($scope), then using Chrome explorer I create beakpoint on line console.log('vuala'). When Chrome stops on this line and in the console I try to execute command console.log($scope) i am getting an error:
Uncaught ReferenceError: $scope is not defined
But if I uncomment line console.log($scope), then this line prints $scope without error.
Why this is happening?

Just out of curiosity (may not be a solution but might be interesting), what happens if you bind that function (that contains the log call) to the scope that contains $scope?
$scope.$on('seachColumn', function (event) {
//console.log($scope);
console.log('vuala');
}.bind ( this )); // or whatever context makes sense.
Naively, the undefined either means $scope doesn't exist yet (which seems unlikely since the other function that calls the function-as-argument succeeds), or the function exists in another context and the log call can't see it (since it is in that function-as-argument).

Related

Cross-origin object when everything is coming from localhost

I'm trying to record every time a user changes a text input on my web page. I'm using the following:
function formInit(socketObject) {
$('input:text').change( (eventObject) => {
console.log(document.domain);
console.log(JSON.stringify($(this)));
//... send stuff via socketObject
});
}
which I'm calling from $(document).ready(). I'm getting the following error on that fourth line, the one that logs $(this):
SecurityError: Permission denied to access property "toJSON" on cross-origin object
despite the fact that console.log(document.domain); returns localhost from both the script and from the master document it's being called from. The only thing that isn't being served up from my flask server on localhost are a couple of libraries (jquery, socketio, cleave) and possibly some components in a bokeh chart, which I'm pretty sure don't qualify as input:text, and certainly haven't been the thing I've been .change()ing in my debugging.
Can anyone suggest where I'm going wrong here, or where I should be looking? Thanks.
The error is because this is not the input:text element as you seem to be expecting, because you're using an arrow function, so lexical scope is not maintained. You either need to change the arrow function to an anonymous function:
function formInit(socketObject) {
$('input:text').change(function() {
// 'this' now refers to the element which raised the event
});
}
Alternatively keep the arrow function, but get a reference to the element from the event which is raised and provided as an argument to the handler function:
function formInit(socketObject) {
$('input:text').change(e => {
// 'e.target' now refers to the element which raised the event
});
}
Aside from the error, stringifying an entire jQuery object is a little odd. It's a better idea to just pull out only the relevant properties you need, something like this:
function formInit(socketObject) {
$('input:text').change((e) => {
console.log(document.domain);
console.log({
id: e.target.id,
value: e.target.value
// other properies here...
});
// send stuff via socketObject...
});
}

Why can't I call function from inside chrome.downloads.onChanged?

I'm creating an extension in chrome for the first time (I'm not a web, or javascript developer). I'm adding onto a codebase that is in an older version of javascript that I've never used (Once I'm at a computer with that codebase, I'll tag which version it is, but I can't remember).
I have a class called DownloadManager, and inside of it I am calling chrome.downloads.onChanged, and within it, I call another function inside of the class, but it can't recognize the class (I think that's the issue).
// Class named DownloadManager
function DownloadManager(someData) {
this._myData = someData;
// function that does a thing, and tests run successfully
this.doAThing = function(someData) {
// Code in here that we assume works, and there's no issues.
}
if(chrome.downloads) {
chrome.downloads.onChanged.addListener(function(delta) {
// Error here
this.doAThing(delta.data);
}
}
}
The error I'm getting is on the this.doAThing(this._myData); line. The error is Error in event handler for downloads.onChanged: TypeError: Cannot read property 'doAThing' of null at <URL>.
I'm assuming it's a scoping issue, and this. doesn't mean anything there, and it can't access doAThing there. I'm certain that the argument taken in is of the same type as the function declared above.
I'll add more data when I'm back in that environment.
Inside your event handler for chrome.downloads.onChanged the this keyword now has a different context than this inside the DownloadManager. It might make sense that since you defined the event handler within the downloadManager that you could share the variable, but that just happens to be a coincidence of "where the code was defined vs where the code is invoked from".
You could probably get away with assigning this to a variable in the main scope:
function DownloadManager(someData) {
this.doAThing = function(someData) {
// Code in here that we assume works, and there's no issues.
}
window.myScope = this;
if(chrome.downloads) {
chrome.downloads.onChanged.addListener(function(delta) {
// Error here
window.myScope.doAThing(delta.data);
}
}
}

Break on variable change in Chrome using AngularJS

Similar to this question, I would like to break on a variable change in Chrome. However, I'm using Angular, so the variable I would like to break on is only defined in the HTML. Its essentially something like this -
<div ng-click="show = !show">...<div>
<div ng-class="{expanded : show}">...
With no code in the controller. So how can I get Chrome to pause when show is changed? I know that I can change the code to a function call that wraps show and then put a breakpoint there, but its an inefficient use of time and I would like to know if there is a way to directly break on variable change.
Well, you can achive the desired feature via console:
First get access to the scope, on which show property is defined. Here
is an explanation of how you can do this.
Then you may observe changes of this scope object via Chrome's Object.observe.
To simplify this process you may define global function like this one:
function breakOn(property, object) {
Object.observe(object, function (changes) {
changes.forEach(function (change) {
if (change.name === property) {
console.log("Property " + property + " changed");
console.log(change);
debugger;
}
});
});
}
And then after step 1 type in the console: breakOn('show', $scope);

Attaching a function to the window object not working in IE8

I have a function defined on the window object somewhat like this
window["functionName"] = function(){
// code here
};
Now whenever I need that function I just call
window["functionName"]();
This works well in all browsers except IE8. IE8 throws an error
SCRIPT438: Object doesn't support property or method 'functionName'
I googled for explainations but didnt find any.
EDIT: After a long time debugging I got the cause of the error
Actually the above function definition was inside another function.
function otherFunction(){
window["functionName"] = function(){
// code here
};
// code here
}
When I moved it outside it looked to work fine.
window["functionName"] = function(){
// code here
};
function otherFunction(){
// code here
}
But I still cannot understand why this weird behaviour?

Having to use $(document).ready() multiple times in same script

I have a script with the following structure:
Test = {
CONSTANTS : {},
VARIABLES : {},
MARKUP : {},
FUNCTIONS : {
init : function () {
// Access variable from different namespace
var all_constants = DifferentNamespace.CONSTANTS; // WORKS
var tester = DifferentNamespace.CONSTANTS.chunk_of_markup; // SAYS UNDEFINED
}
},
init : function () {
// Call real init() function
$(document).ready(function () {
Test.FUNCTIONS.init();
});
}
};
$(document).ready(function () {
Test.init();
});
If I remove either of the $(document).ready(..) function calls, when I try to access a constant from a different namespace it is undefined; with both is works well.
As you can see I'm using two init() functions, one it just to neaten up the call to init because I have wrapped functions inside an additional object.
If I remove the function that is on the same level as CONSTANTS, VARIABLES etc and try to call the init() within Test.FUNCTIONS it still does not work.
Edit:
If i console.log(all_constants) I get the full object (with .chunk_of_markup) but if I console.log(tester) is get undefined. If i wrap tester i get []
I should also note that the other namespace gets the markup from a seperate file.
Any ideas why?
Having two document ready doesn't make a difference here. You could have one document.ready and/or call Test.FUNCTIONS.init directly and all should work, and the fact that they are in different namespaces doesn't matter as well.
As for why you're getting undefined, I think it is probably because your chunk_of_markup variable is actually undefined at that point. My guess is that you're getting the value for it through AJAX and so the call is done asynchronously which means the DOM will be ready before it actually returns a value. When you use the Debugger then the value is evaluated at the point of time where you run the command so by then, the async call already returns successfully (it's a race condition, if you're fast enough and your AJAX is slow then you can still get undefined, and it's also why 2 ready functions happen to make it slow enough for the AJAX call to return but it's still unreliable).
In all cases, if my theory is correct, then you need to hook to the callback of the AJAX request rather that DOM ready event, this is the only place where you can guarantee that your variable is defined.
Why not call the function init() in the document Handler itself.. I don't think that will lead to the same problems.. You can remove the Test.init() completely as it does not seem to do anything in here
Test = {
CONSTANTS : {},
VARIABLES : {},
MARKUP : {},
FUNCTIONS : {
init : function () {
// Access variable from different namespace
var all_constants = DifferentNamespace.CONSTANTS; // WORKS
var tester = DifferentNamespace.CONSTANTS.chunk_of_markup; // SAYS UNDEFINED
}
}
};
$(document).ready(function () {
Test.FUNCTIONS.init();
});

Categories

Resources