class Dashing.Hacircledimmer extends Dashing.Widget
setLevel: ->
levelToSet = '10'
$.post '/homeassistant/dimmerLevel',
widgetId: #get('id'),
command: levelToSet,
(data) =>
json = JSON.parse data
ready: ->
meter = $(#node).find(".meter")
meter.knob
'release': (v) ->
#setLevel
onData: (data) ->
I am trying to call function setLevel after initializing meter.knob but I keep getting an error saying that the function does not exist. Ideally I would like to pass v to the function setLevel.
I did not include the constructor etc.. to keep the code short.
Can someone point out my error? Sorry, I am new to coffeescript and would really appreciate if anyone can help me out.
Thanks!
Try changing 'release': (v) -> to 'release': (v) =>
(-> vs =>)
Related
If "a_b" does not exist then the following code throws back undefined - which is what I want:
var abc= json.reduce((a,c) => a.concat({xyz:c.a_b}), [])
However, if I do the following code and look for "media" within "a_b" that does not exist then I get a failure "Cannot read property 'media' of undefined".
var abc= json.reduce((a,c) => a.concat({xyz:c.a_b.media}), [])
Why is this the case?
In both cases "a_b" does not exist yet it is ok with the code if I just call that but not if I try and look for a property within it.
Is there a way to get around this?
For example, I am trying to use "|| null" but that doesn't seem to work within a concat, as below.
var abc= json.reduce((a,c) => a.concat({xyz:c.a_b.media || null}), [])
Don't use concat method it will create a new array instance, use push instead:
var abc = json.reduce((a, c) => {
a.push({ xyz: c.a_b && c.a_b.media });
return a;
}, []);
I am working with Ionic2 and Meteor. I do however have a Javascript/Typescript issue relating to the scope of the this object.
I have read that I should use bind when I don't have handle on this at the appropriate level.
I probably don't understand the concept, because I try the following, but get an error trying to call a function.
this.subscribe('messages', this.activeChat._id, this.senderId, () => {
this.autorun(() => {
let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
promiseMessages.then((messageData: Mongo.Collection<Message>) => {
messageData.find().forEach(function (message: Message) {
setLocalMessage.bind(message);
});
});
});
and
private setLocalMessage(message: Message): void {
this.localMessageCollection.insert(message);
}
I get the following error when I try build the app:
ERROR in ./app/pages/messages/messages.ts
(72,19): error TS2304: Cannot find name 'setLocalMessage'.
UPDATE
Thank you for the advise below.
I am now using the following, and it works.
let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
promiseMessages.then((messageData: Mongo.Collection<Message>) => {
messageData.find().forEach((message: Message) => {
this.setLocalMessage(message);
});
});
I have read that I should use bind when I don't have handle on this at the appropriate level.
That's a bit outdated now, better have a look at How to access the correct `this` context inside a callback? these days which also shows you how to use arrow functions.
You're getting the error message because setLocalMessage is not a variable but still a property of this so you have to access it as such. There are basically three solutions in your case:
bind
messageData.find().forEach(this.setLocalMessage.bind(this));
the context argument of forEach (assuming it's the Array method):
messageData.find().forEach(this.setLocalMessage, this);
another arrow function:
messageData.find().forEach((message: Message) => {
this.setLocalMessage(message);
});
There are a few things wrong here.
In ES6 (and thus TypeScript), you need to refer to instance members using explicit this, such as this.setLocalMessage. Just writing setLocalMessage is invalid no matter where the code is.
Inside a function, the this object will probably not be what you expect anyway. You need to capture the this object from outside the function and put it in a variable, like so:
this.subscribe('messages', this.activeChat._id, this.senderId, () => {
this.autorun(() => {
let self = this;
let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
promiseMessages.then((messageData: Mongo.Collection<Message>) => {
messageData.find().forEach(function (message: Message) {
self.setLocalMessage(message);
});
});
});
Alternatively, you can use an arrow expression, in which this is the same as what it is in the code around it:
this.subscribe('messages', this.activeChat._id, this.senderId, () => {
this.autorun(() => {
let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
promiseMessages.then((messageData: Mongo.Collection<Message>) => {
messageData.find().forEach(message => this.setLocalMessage(message));
});
});
});
It's not an issue of TypeScript itself. Without it, the code will just fail at runtime.
I simply wanna call a function which returns a Url as a string from an inherited class which is dynamically build:
class #Api
DEFAULT_API_VERSION: 'v2'
constructor: ->
#setVersion(#DEFAULT_API_VERSION)
return
setVersion: (version) ->
#version = version if version?
getVersion: ->
#version
baseUrl: ->
"http://api#{#getVersion()}.mysite.com/api/#{#getVersion()}/"
class #ApiArticle extends Api
constructor: ->
super
return
articlesUrl: ->
"#{#baseUrl}news/articles".toString()
This is the test in the parent class which is PASSING
it 'provides the baseUrl for Api calls', ->
api = new Api()
expect(api.baseUrl()).toEqual('http://apiv2.mysite.com/api/v2/')
This is my test and it FAILS
it 'returns all news articles url', ->
new ApiArticle()
url = api_article.articlesUrl()
expect(url).toEqual 'http://apiv2.mysite.com/api/v2/news/articles'
The result I get from this spec, it should be a String but receives this:
Expected
'function () { return "http://api" + (this.getVersion()) + ".mysite.com/api/" + (this.getVersion()) + "/"; }news/articles'
to equal
'http://apiv2.mysite.com/api/v2/news/articles'.
Is there something missing? Do I have to explicitly render / calculate?
I am quite new to JS and Coffee.
Thank you!
Here
articlesUrl: ->
"#{#baseUrl}news/articles".toString()
You wanted to call the method baseUrl in the superclass, but instead you only referred to it. So then the function itself gets toStringed, and "news/articles" is appended. This results in the string: function () { return "http://api" + (this.getVersion()) + ".mysite.com/api/" + (this.getVersion()) + "/"; }news/articles, which is what you see in the test error.
Fix it by actually calling baseUrl, not just referring to it:
articlesUrl: ->
"#{#baseUrl()}news/articles".toString()
You can then remove the useless toString call.
You might want to consider renaming the method getBaseUrl to avoid making this mistake again.
B = require 'backbone'
U = require 'underscore'
o = {}
U.extend o, B.Events
o.on 'e', console.log
setTimeout o.trigger, 5000, 'e', 'Hi!'
Why did Nodejs console not log for the delayed Backbone #trigger above?
#Edit
Q = require 'q'
d = Q.defer()
d.promise.then console.log
setTimeout d.resolve, 5000, 'Hi!'
This worked flawlessly. But why did the console not log if Q #resolve was wrapped in the anonymous function below,
setTimeout (-> d.resolve 'Hi!'), 5000
#Edit 2
Actually the wrapped version Q #resolve also worked if being invoked at first and once.
Why the plain version Q #resolve worked while Backbone #trigger didn't, is the only remaining question.
#Edit 3
R = require 'rx'
src = new R.BehaviorSubject 0
dst = src.map (v) -> v + 1
dst.subscribe console.log
setTimeout src.onNext, 5000, 1
Rx #onNext had similar problem and solution to Backbone #trigger.
All above can be sourced to the varying this context, e.g. a bare version shows the problem below,
o =
f: ->
g: -> #f()
setTimeout o.g
then,
TypeError: Object [object Object] has no method 'f'
The wrapped version below thus goes through.
setTimeout -> o.g()
Below shows this context switch to cause the problem and the wrapper to solve it,
f = (g) -> g.apply #
o =
x: 'Hi!'
g: -> console.log #x
f o.g # undefined
f -> o.g() # 'Hi!'
#Edit 4
Additionally, Coffeescript => binding to this varies to -> below,
x = 'Hi!'
o = f: => #x
console.log o.f() # Hi!
console.log -> o.f() # undefined
Because when you pass o.trigger as an argument to setTimeout you execute trigger function not as an method for o object but instead you execute it in global scope. That is in this case this inside trigger will point not to o but to global object.
So before passing o.trigger as an argument to setTimeout you need to wrap it in anonymous function.
Unfortunately I'm not good in Coffee Script but I can show you how your code should look like in pure JavaScript:
var B, U, o;
B = require('backbone');
U = require('underscore');
o = {};
U.extend(o, B.Events);
o.on('e', console.log);
setTimeout(function () {
o.trigger('e', 'Hi!');
}, 5000);
Hope this will help. Good luck.
A website has the following code:
var Items = {
drop: function (a, b, d) {
if (!(typeof a == "undefined" || typeof sockets[a.id] == "undefined")) {
SSocket.send(sockets[a.id], {
action: "item_drop",
data: {
id: d
}
});
Inventory.add(a, d)
}
},
give_to_player: function (a, b) {
Items.drop(a, void 0, b)
},
take_from_player: function (a, b) {
var d = clients[a];
Inventory.remove(d, b);
Player.send_inventory(d.id)
},
};
I am trying to replace the give_to_player property with my own function using a userscript. However, I am having zero luck doing so. I am familiar with javascript injection and the variable scope.
I have tried the following:
Object.defineProperty(window.Item, 'give_to_player', {
value:
function(a,b){
console.log('Change occured');
}
});
This does not generate any errors, however the change does not take hold and the console remains empty. I have tried Object.defineProperties as well with no luck.
Finally the following code failed to produce results either:
window.Item.give_to_player = function(a,b){ console.log('Change occured');};
Does anyone have any suggestions?
I am using Chrome to run my userscripts.
The second method would work if you change the name to Items with a s and drop the window in the method to just Items.give_to_player = function(a,b){ console.log('Change occured');};.
EDIT: the var in var Items makes the method not accessible thru the window scope. if the var was dropped this window.Items.give_to_player won't throw error but since its there you'll not need to use the window in front of Items.(if that makes sense)
JSFIDDLE
side note: your error
window.Items.give_to_player = function(a,b){ console.log('Change occured');};
// Uncaught TypeError: Cannot set property 'give_to_player' of undefined
I really don't know how the rest of code looks like (if that object is in some particular scope, deeply nested or what) but if Items object is in global scope you can define AFTER that object (and its properties definition) again that property and that should override the previous one:
Items.give_to_player: function () {
//write your own function
}
But I'm not sure if this will work as long as I have so little information.