Calling coffeescript functions from console - javascript

Playing a little with coffeescript and Rails 3.1.0.rc4. Have this code:
yourMom = (location) ->
console.log location
yourMom "wuz hur"
When the page loads, this outputs "wuz hur" properly. But when I try to call
yourMom("wuz hur")
from the chrome js console (as I do sometimes to test normal JS functions), I get a "ReferenceError: yourMom is not defined"
Are functions generated by coffeescript available in this way?

an easier way to share global methods/variables is to use # which means this.
#yourMom = (location) ->
console.log location
yourMom "wuz hur"
Nicer syntax and easier to read, but I don't encourage you to create global methods/variables

This happens because coffeescript wraps everything in a closure. The JavaScript output of that code is actually:
(function() {
var yourMom;
yourMom = function(location) {
return console.log(location);
};
yourMom("wuz hur");
}).call(this);
If you want to export it to the global scope, you can either do:
window.yourMom = yourMom = (location) ->
console.log location
or
this.yourMom = yourMom = (location) ->
console.log location

I'm not sure about Rails but the CoffeeScript compiler has an option (--bare) to compile without the function wrapper. Fine for playing but it does pollute the global scope.

this link might solve your problem
Rails - Calling CoffeeScript from JavaScript
Wrap your functions in a unique namespace and then you can acess these functions from wnywhere

Related

How can I use modules in the browser, but also refer to variables and functions from within DevTools?

I have my HTML setup like this:
<script type="module" src="main.js"></script>
and all the ES6 modules work fine. The only problem is I now can't refer to anything from within DevTools (like using the Console and typing in a variable to see it's value or using a function manually).
How do I import modules whilst being able to use the DevTools? Thanks!
One way to make a variable accessable within DevTools is to create it on the window object:
// Variable in your module
var importantNumber = 1;
window.importantNumber = importantNumber;
This method works fine if you just have a couple of variables, but if you need to have access to a lot more variables within DevTools, I would recommend you go to the sources-tab in DevTools, search for your module and adding a breakpoint. When the execution pauses, you have access to all the variables within that module on the DevTools console.
If you want to be able to refer to variables created within the module from the console's global scope, you'll have to deliberately expose each such variable that you want to be visible from the console. Either assign each variable to window (probably not a good idea - the whole point of modules is to make things more modular, without global pollution), or perhaps assign a single object to window, to which you assign module variables. For example:
// in the console:
setTimeout(() => {
window.myModule.foo();
console.log(window.myModule.bar);
});
<script type="module">
function foo() {
console.log('doing foo');
}
const bar = 'a string bar';
const thisModule = { foo, bar };
window.myModule = thisModule;
// If you ever reassign variables, you'll have to reassign them on thisModule too
// or, only reference and reassign properties of thisModule, rather than create independent variables
</script>
For anyone else interested, if you're comfortable with it, use a bundler like Webpack. I don't believe (at least at this point) that the browser will by itself be able to use the DevTools on modules (the other solutions are quite janky, and aren't fantastic to work with).
Hopefully in the future, when all major browsers will be able to support ES6 modules without a bundler, we'll be able to use DevTools.
Using a Helper
I personally use a little helper function in development that allows me to expose a bunch a variables in a single expression. For example, it makes the following two blocks equivalent:
window.playerOne = playerOne;
window.someClass = someClass;
window.localData = localData;
globalize({playerOne, someClass, localData});
The helper looks like this:
const globalize = function(variables) {
Object.entries(variables).forEach(([name, value]) => window[name] = value);
};

Why is 'this' undefined in the debugger but printable in a console.log?

When setting a breakpoint on the console.log statement, why would this be undefined in the debugger but the statement print with no issues? Am I missing something in regards to scope here?
export class OptionsSidebarComponent {
...
public filters: Object = new Object();
...
public generateFilters() {
for (let property in this.terms) {
if (this.terms.hasOwnProperty(property) && this.terms[property] !== null) {
if (!this.filters.hasOwnProperty(this.productGroup.id)){
this.filters[this.productGroup.id] = new Filters();
}
this.terms[property].forEach((term) => {
console.log(this.filters);
});
}
}
}
}
With typescript While debugging, keep in mind that transpilers can rename variables. Using the original name in the console without sourcemaps that include renaming will show you undefined even if the original value isn't. Make sure you use the transpiled name in watches or console commands.
When you're referencing this with your console.log statement inside its own class, you're using it in its relevant scope. Depending on the framework you are using, different terms are used to reference your class... AngularJS used $scope- Angular 2+ uses this to reference the current class (or current scope/context).
When you use this in your debugger you're using it outside of its scope. It no longer references the class you intend it to.
Each one of your components in Angular uses this to reference itself. Here's an article to explain in further detail: https://angular-2-training-book.rangle.io/handout/features/refresher_on_this.html
If we simplify it to basic javascript and look at your class as just a function a good example would be this:
function example(){
var anything = 10;
console.log(anything); //output: 10
}
console.log(anything); //undefined! we're out of scope :)
So looking at it from this perspective, this is nothing magical. It's just provided to us by Angular to make our references to other things inside our components easier.

JS namespace Netbeans variable not declared

When I was defining a namespace in JavaScript, Netbeans gave a global variable not declared error while I think it shouldn't. Why is this?
Demonstration code:
var MyNamespace = new function () {
var MyClass = function () {};
MyClass.SOME_CONSTANT = 9; // MyClass not defined
this.MyClass = MyClass; // MyClass not defined
};
I checked and this code works in IE (document mode IE 5) and Edge 13. The code is a Module Pattern like syntax like in this answer.
EDIT: first declaring a variable is probably not useful, for a function inside the namespace will sometimes change the local variable instead of that in the public namespace, am I right? Still, I wonder why Netbeans gives me an error.
You can add a comment to the top which will tell Netbeans to ignore the error.
For example when using angular
/* global angular */
Will prevent the error for things like
angular.module('Module', []);
I am using NetBeans IDE 8.2 (Build 201705191307)
If you want to completely ignore this type of error, I would suggest this:
Tools > Options > Editor > Hints > Uncheck "The global variable is not declared"
It worked for me.

Where to place javascript functions in Meteor applications

In Meteor we normally attach javascript functions to Templates. Where do we place standard javascript functions?
For instance, in one of my apps I have a UserInfo.js file which has a bunch of javascript functions for handling users logging in and getting user information.
Below are two of my functions in UserInfo.js
File is located in the client/scripts folder:
isAdminById = function(userId) {
var user;
user = Meteor.users.findOne(userId);
return user && isAdmin(user);
};
isAdmin = function(user) {
if (!user || typeof user === 'undefined') {
return false;
} else {
return !!user.isAdmin;
}
};
When I run the app and call isAdmin() from the browser console it says:
ReferenceError: isAdmin is not defined
---- Edit ----
It seems the problem was fixed temporarily when I placed the javascript file under the client/compatibility folder but now the issue has resurfaced. The only thing I remember changing was calling >> Meteor Reset
More Info:
I think the issue arises when I use coffeescript. When I convert my coffeescript files to js files everything seems to work.
You need to declare coffeescript variables as global with #:
#isAdmin = user -> ...
This is due to how Meteor variable shadowing works in connection with coffeescript automatic variable declaration.
Coffeescript by default does the "smart" variable declaration by itself - basically by placing var variableName in the first place in javascript where the variable is visible. In your case, this causes isAdmin to be declared by var in js, and therefore it's scoped to the file.
Using # char supersedes this default behavior by binding the variable to this, global or window object instead.
Your code is correct, it's probably a load order problem.

How to pass an argument to a Javascript Module?

I want to use a Javascript Module (JSM) in a single window of my Xul application, so I can load the resource as I need it.
But, I need to pass the window to the JSM, and I don't know how to do it. Follows my attempt:
In my resource.jsm:
var EXPORTED_SYMBOLS = ["hello"];
function hello(win) {
win.alert("ALERT FROM JSM!");
}
calling in my window with:
Components.utils.import("resource://module/resource.jsm");
hello(window);
but I get:
win is undefined
in the resource.jsm.
Any idea how to make it work?
It might be causing problems that you named the parameter for your hello function to be window. While window isn't a reserved word, most browser environments treat it as an unassignable constant of sorts. Try:
function hello( obj ) {
obj.alert("ALERT FROM JSM!");
}
in your module and then invoke it with hello(window), hello(document.window), or hello(this)
After reading the Javascript Module documentation, it looks like you'll need to create an object within the module and then change it's property by reference. So in your JSM:
var EXPORTED_SYMBOLS = ["params", "hello"];
params = {
win: this
};
function hello() {
params.win.alert("ALERT FROM JSM!");
}
Then you'd invoke by first assigning the window to that parameter and then calling the function:
Components.utils.import("resource://module/resource.jsm");
params.win = window;
hello();
Note: I am not familiar enough with JSMs to know if there's a better way to do this, but this should work.

Categories

Resources