I have function defined like this
casper.executeRemote = (fn,params)->
->
try
fn.apply(this,params)
catch e
console.log(e)
getLinks = ->
elems = document.querySelectorAll('#pagination-flickr a')
and i am calling the function like below
casper.then ->
all_links = #evaluate #executeRemote getLinks
casper.log all_links,'debug'
However I get the below error when i try to run this in casperjs
ReferenceError: Can't find variable: fn
The same code works fine, if i try in a browser console(compiled js). What is that I am doing wrong?
Of course they work, but not at the border to the page context:
Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.
Closures, functions, DOM nodes, etc. will not work!
Thankfully there is the toString function on Functions. So, you can change your code a little to account for passing the function as a string and evaling inside of the page context.
(Untested) example:
casper.executeRemote = (fn,params)->
fn = eval('('+fn+')')
try
fn.apply(this,params)
catch e
console.log(e)
getLinks = ->
elems = document.querySelectorAll('#pagination-flickr a')
casper.then ->
all_links = #evaluate(#executeRemote, getLinks.toString())
casper.log all_links,'debug'
Based on #Artjom's answer. I modified the code as shown below, then it works
executeRemote = (fn,params)->
->
try
fn.apply(this,params)
catch e
console.log(e)
getLinks = ->
elems = document.querySelectorAll('#pagination-flickr a')
links = (link.href for link in elems)
remoteWrapper = (excRm,gL)->
excRm=eval('('+excRm+')')
gL=eval('('+gL+')')
fn=excRm(gL)
fn()
casper.on 'remote.message',(message)->
#echo message
casper.then ->
all_links = #evaluate remoteWrapper, executeRemote.toString(), getLinks.toString()
casper.log all_links,'debug'
I am trying to write a indexeddb function "delete". It should read like this in JS:
var transaction = db.transaction('objectStore','readwrite');
var objectStore = transaction.objectStore('objectStore');
objectStore.delete(id);
However, when I write it in CS:
transaction = db.transaction 'objectStore','readWrite'
objectStore = transaction.objectStore 'objectStore'
objectStore.delete(id)
Of course it outputs:
...
objectStore["delete"](id);
I didn't write a method for IDBTransaction called "delete", but I have to use it. How can I keep CS from escaping the "delete" method and turning it into a "delete" key in an object?
Use backticks to pass through bare Javascript:
`objectStore.delete(id)`
will be compiled through verbatim. Try it here at my favorite site for interpreting between CS and JS: http://js2coffee.org/#coffee2js
transaction = db.transaction 'objectStore','readWrite'
objectStore = transaction.objectStore 'objectStore'
`objectStore.delete(id)`
becomes
var objectStore, transaction;
transaction = db.transaction('objectStore', 'readWrite');
objectStore = transaction.objectStore('objectStore');
objectStore.delete(id);
Why do you care that the JavaScript version is objectStore["delete"](id)? That's the same as objectStore.delete(id).
For example, if you say this in CoffeeScript:
class B
m: (x) -> console.log("B.m(#{x})")
class C extends B
c = new C
c.m('a')
c['m']('b')
The last two lines come out as this JavaScript:
c.m('a');
c['m']('b');
but they both call the same method.
Demo: http://jsfiddle.net/ambiguous/XvNzB/
Similarly, if you say this in JavaScript:
var o = {
m: function(x) { console.log('m', x) }
};
o.m('a');
o['m']('b');
The last two lines call the same method.
Demo: http://jsfiddle.net/ambiguous/Y3eUW/
I am confused about how to reference the outer scope from an inner scope in this case:
that = #
#collection.bind 'reset', ->
that.render()
Is there any CoffeeScript construct that makes the that = # look better?
From what I can tell, this is what the fat arrow is for:
#collection.bind 'reset', =>
#render()
It compiles into:
var _this = this;
this.collection.bind('reset', function() {
return _this.render();
});
How do I write this in coffee script?
function setUpDialogForms() {
setUpListForm();
setUpUpdateForm();
}
I have tried
setUpDialogForms -> setUpListForm(); setUpUpdateForm()
Provided the setUpListForm and setUpUpdateForm functions are defined somewhere, you can use:
setUpDialogForms = ->
setUpListForm()
setUpUpdateForm()
setUpDialogForms()
Found it out.
setUpDialogForms = () ->
setUpListForm()
setUpUpdateForm()
return
Which returns
var setUpDialogForms;
setUpDialogForms = function() {
setUpListForm();
setUpUpdateForm();
};
is there a way to return an object from a comprehension in coffeescript? something so that i could express this:
form_values = () ->
ret = {}
ret[f.name] = f.value for f in $('input, textarea, select')
return ret
like this:
form_values = () -> f.name, f.value for f in $('input, textarea, select')
i'd like to construct a single object (not an array of objects). so if the markup looks something like this:
<form name=blah>
<input type=text name=blah1 value=111 />
<textarea name=blah2>222</textarea>
<select name=blah3>
<option value=333a>
<option value=333b>
</select>
</form>
the returned object would be something like this:
{
blah1: '111',
blah2: '222',
blah3: ''
}
form_values = new ->
#[f.name] = f.value for f in $ 'input, textarea, select'
this
or
form_values = new class then constructor: ->
#[f.name] = f.value for f in $ 'input, textarea, select'
Nope. Comprehensions only return arrays in CoffeeScript. Search the issue tracker for object comprehensions, and you'll find several proposals, but none were found suitable.
Check the functional library underscore and the extension _.mash from this mixin:
form_values = ->
_($('input, textarea, select')).mash f -> [f.name, f.value]
Using underscore's object function, you can do this:
form_values = _.object([f.name, f.value] for f in $('input, textarea, select'))
This has already been answered but probably lack of some explanations as this idiom is rather cryptic at first sight:
form_values = (new -> #[f.name] = f.value for f in $ 'input, textarea, select'; #)
// ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
// create with |
// a new that |
// empty anonymous |
// object constructor |
// don't forget -/
// to return the
// newly created object
The key idea is to create an empty object (new) with an anonymous constructor (-> ...) that will create the various fields.
CoffeeScript's creator suggests using a helper function to convert an array of pairs into an object:
form_values = toObject([f.name, f.value] for f in $('input, textarea, select'))
This is arguably the most readable way of doing it, within the current language syntax. It's also very similar to how Python and other languages do it, except for the missing syntactic sugar.
The helper function can be easily written once, using for example the technique from #matyr's and #Sylvain's answers:
// Create a new object from an array of [key, value] pairs.
toObject = (pairs) ->
new -> #[key] = value for [key, value] in pairs; #
I believe you can do this with no added libraries right in CoffeeScript.
It should be something to the effect of:
$('input, textarea, select').each (item) => #form_values || #form_values = {}; #form_values[$(item).name] = $(item).value
You could simplify the syntax of that by pre-creating the form_values:
form_values = {}
$('input, textarea, select').each (item) -> form_values[$(item).name] = $(item).value
Here is a lengthier response with canned examples:
Take a very simple example where you wanted to map the obj to name value:
items = [ { a: 1 }, { b: 2 }, { c: 3 } ]
items.map((item) -> {name: Object.keys(item)[0], value: item[Object.keys(item)[0]]})
[ { name: 'a', value: 1 },
{ name: 'b', value: 2 },
{ name: 'c', value: 3 } ]
Note that the above is not really an Object comprehension, just demonstrating an example.
Now let's say there is a bit more structure and you just want to map a known unique key:
items = [{key: "abc", someVar: 1}, {key: "def", someVar: 2}]
In Python you'd do something simple like this: {x['key']:x for x in items}
In CoffeeScript you can get all of this down to one single line though with a caveat:
items.forEach (item) => #x || #x = {}; #x[item['key']] = item
{ abc: { key: 'abc', someVar: 1 },
def: { key: 'def', someVar: 2 } }
In the above code x was not previously defined in the scope, so using => and # allowed us to bind x with the #x || #x = {} if not previously found, then set the key.
If you don't want to use => and # you have to define x beforehand:
x = {}
items.forEach (item) => x || x = {}; x[item['key']] = item
{ abc: { key: 'abc', someVar: 1 },
def: { key: 'def', someVar: 2 } }
Not to beat a dead horse, but I personally thing this is readable and satisfies the 'one line' requirement without needing extra modules:
form_values = {}; form_values[f.name] = f.value for f in $('input, textarea, select')
Don't forget you can still use a semi-colon to combine lines in Coffeescript!