$timeout cannot find my variable - angularjs

Ok using Angular and Coffeescript here the following works:
angular.module 'someApp'
.factory 'someFactory', ($timeout) -> new class SomeClass
constructor: ->
#humans = 1
findHuman: ->
$timeout((=>#humans+=1), 1000)
Which is fine I guess but I'd like to have the #humans+=1 part somewhere else.
So why does this not work?
angular.module 'someApp'
.factory 'someFactory', ($timeout) -> new class SomeClass
constructor: ->
#humans = 1
findHuman: ->
$timeout(addOneHuman, 1000)
addOneHuman = =>
#humans+=1
Testing around with console.log or $log, adding #'s here and there, -> instead of => sometimes the variable humans is NaN, sometimes it is undefined.
What do I have to do to make this work? :)

I don't know the Angular side of things that well but I think your problem is that this:
addOneHuman = =>
doesn't do what you think it does. Something like this:
class C
f = ->
m: ->
creates f as essentially a private function within C. The JavaScript version is equivalent to:
var C = (function() {
function C() {}
var f = function() {};
C.prototype.m = function() {};
return C;
})();
so f is just a variable that references a function and f is in scope for anything in C. Changing it to:
f = =>
doesn't do anything because there is no this that applies when f is defined. On the other hand, m is a method (note the C.prototype.m in the JavaScript version) so there is an applicable this and m: => can do something useful.
You just want your addOneHuman to be a method rather than a plain old function:
addOneHuman: =>
# ---------^
There might be something useful to you in a couple of my other answers:
coffeescript scope of variable assignment vs property assignment in object's other properties
How to make method private and inherit it in Coffeescript?

Related

unexpected else in coffeescript when using super

I am using backbone.js, writing it in coffeescript but get this error and am not able to resolve it !
Snippet of the code:
module.exports = class CoreModel extends Backbone.Model
destroyed: false
# Helper to toggle the state of boolean value (using not)
toggle: (key) -> #swap key, invert
# Helper to change the value of an entry using a function.
swap: (key, f) -> #set key, f #get key
toJSON: -> if #destroyed then 'DESTROYED' else super
Error:
[stdin]:11:45: error: unexpected else
toJSON: -> if #destroyed then 'DESTROYED' else super
^^^^
Not sure why this is an unexpected else!
If you are using coffeescript 2, then you need to use parenthesis with super(). The error message here should really be more helpful.
You can read about it in the docs.
module.exports = class CoreModel extends Backbone.Model
destroyed: false
# Helper to toggle the state of boolean value (using not)
toggle: (key) -> #swap key, invert
# Helper to change the value of an entry using a function.
swap: (key, f) -> #set key, f #get key
toJSON: -> if #destroyed then 'DESTROYED' else super()
If you find a situation where you want the old behavior (all arguments are forwarded onto the super call, then you can use this:
foo: -> super arguments...

Swift: Changing value of global variable via function.

I'm trying to change the value of a global variable transferredData in the function didTransferData(_ data: Data?). My code looks like this:
var transferredData: [Double] = [0.0]
func didTransferData(_ data: Data?) {
var dataArray = [CUnsignedChar](repeating:0, count: (data?.count)!)
data?.copyBytes(to: &dataArray, count: dataArray.count)
let dataInt = dataArray.filter({ Int(String($0)) != nil }).map({ Int(String($0))! })
let dataDouble = dataInt.map { Double($0) }
print("Data double: \(dataDouble)")
transferredData = dataDouble
}
Printing transferredData inside of didTransferData returns the correct array, containing all values of dataDouble. But when I try to access it in this function later on
func returnData() -> [Double]{
print("return Data: \(transferredData)")
return transferredData
}
it returns [0.0]. I'm not sure if I'm missing something crucial here, but I thought that even if I change the value of a global variable in a function, the new value should be accessible for every other functions, too.
Thanks for any advice!!
You said that this code is inside a class. The variable transferredData is not a global, it is a member variable.
There is one of these per object of the class. I suspect that you are not using the same object to make these two calls.
You could make the member shared between all objects by declaring it static, but I think it would be better to leave as is and arrange to use the same object.
EDIT: based on comment
If you write the code
let centralInstance = CentralViewController()
You will get a new object with its own transferredData member initially set to [0.0]. You need to either
Get a reference to the same VC object that has the data
Store the data some where else in an object that you can get back (since the VC might be gone)
To hack something that works (not recommended, but to help understand)
You could move transferredData out of the class and make it an actual global variable. I would do this only to help you get past this issue and understand what's going on.
You could also make it static, which makes all of the VC's share the same instance of the transferredData
When you understand what is going on, you can try to do something a little better (at least move it to its own model object, and not in the VC at all). The next simplest thing is some kind of singleton to manage it -- this is just a glorified global variable but puts you more on the road to a more typical solution.
Where is the problem:
$ swift
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
1> var data:[Double] = [0.0]
2.
3. class MuckWithData {
4.
5. func showData () -> [Double] {
6. print ("Data: \(data)")
7. return data
8. }
9.
10. func modifyData () {
11. data = [1.0]
12. }
13. }
data: [Double] = 1 value {
[0] = 0
}
14>
15> var mucked = MuckWithData()
mucked: MuckWithData = {}
16> mucked.showData()
Data: [0.0]
$R0: [Double] = 1 value {
[0] = 0
}
17> mucked.modifyData()
18> mucked.showData()
Data: [1.0]
$R1: [Double] = 1 value {
[0] = 1
}
Probably your computation for dataDouble is actually [0.0] and thus it appears that transferredData didn't change, but it did.

Does AngularJS have a function like eval?

Does AngularJS have any function or method similar to eval?
I need to get the value of a previously-defined variable, e.g.:
data.mess_5 = "Hello"
c = 5
x = eval( "data.mess_" + c )
Angularjs is javascript, so you can use eval, assuming your var is on the global scope. However, in this particular case (and most other cases), eval is the wrong tool for the job.
data.mess_5 = "Hello"
c = 5
x = data['mess_' + c]
Check the $parse function (taken from Setting dynamic scope variables in AngularJs - scope.<some_string>)
var the_string = 'life.meaning';
// Get the model
var model = $parse(the_string);
// Assigns a value to it
model.assign($scope, 42);
// Apply it to the scope
$scope.$apply();
console.log($scope.life.meaning); // logs 42

Can't sum values in Angularjs if one value is an empty string

I am building a simple Appgyver mobile app using Angularjs and Coffeescript - I'm a beginner with both of these.
I wish to determine the total cost for a list of up to 20 items stored on the database. However, there may be less than 20 items.
I have attempted to do the calculation with ng-bind, which works perfectly as long as all strings contain values. However, if there are less than 20 pairs (values go up to q20 and p20) then the calculation returns NaN.
I would like to determine the total of all existing values for the list. I have looked at numerous examples on stackoverflow, Angularjs.org and other sites and have experimented with a myriad of alternative methods, however I think I lack the basic understanding of how to make this work. Any help would be appreciated.
This is the code I have used, shortened to 3 pairs instead of 20:
<span ng-bind="client['q1'].price * client['p1'].price + client['q2'].price
* client['p2'].price + client['q3'].price * client['p3'].price"></span>
This is the existing controller:
angular
.module('client')
.controller("ShowController", ($scope, Client, supersonic) ->
$scope.client = 0;
$scope.showSpinner = true
$scope.dataId = undefined
_refreshViewData = ->
Client.find($scope.dataId).then (client) ->
$scope.$apply ->
$scope.client = client
$scope.showSpinner = false
supersonic.ui.views.current.whenVisible ->
_refreshViewData() if $scope.dataId
supersonic.ui.views.current.params.onValue (values) ->
$scope.dataId = values.id
_refreshViewData()
$scope.remove = (id) ->
$scope.showSpinner = true
$scope.client.delete().then ->
supersonic.ui.layers.pop()
)
I think you are overloading (in the linguistic sense, not the coding sense) ng-bind. Doing all of that code in your HTML is messy and is not what it was created for. You would be better off doing the math in your controller, and then referencing it in ng-bind. You have only 3 pairs here, but you say you have 20, and could be more, so do it that way:
<span ng-bind="totalPrice"></span>
And in your controller:
var setTotalPrice = function() {
var ret = 0, i, maxClient = 6, client = $scope.client; // or however else you keep track of them
for (i=1;i<=maxClient;i++) {
if (client['q'+i] && client['q'+i].price && !isNaN(client['q'+i].price) &&
client['p'+i] && client['p'+i].price && !isNaN(client['p'+i].price)) {
ret += (client['q'+i].price * client['p'+i].price);
}
}
$scope.totalPrice = ret;
};
$scope.setTotalPrice = setTotalPrice;
setTotalPrice();
Just call setTotalPrice in your controller whenever you want, or on an ng-click.
Please don't abuse ng-bind for calculations! Instead calculate the values in your controller and bind the resulting value.
Problem with your code is -if any of the values is not a number your result becomes NaN. In the controller function you check for the presence of value and then operate. You may want to check whether the value is non-null as well as a number string and then operate on it.

Are parents filters available to all sub modules?

var x = angular.module("x", ["a","b","c"]);
x.filter('myfilter', func);
x.directive('myDirective', func);
var a = angular.module("a",[]);
a.filter('alfa', func);
a.controller('userController', func);
Is myFilter and myDirective also available to userController?
is alfa available to x?
Module x can access the filter of module a as it has listed it as a dependency. Module a however can not access the filter or directive of x, as there is no dependency on the module. Angular handles it for you!
Refer to: http://docs.angularjs.org/guide/di && http://docs.angularjs.org/guide/module
The code below:
var x = angular.module("x", ["a"]);
x.filter('myFilter', function(){});
x.directive('myDirective', function(){})
x.controller("xCtrl", function(alfaFilter) {
})
var a = angular.module("a",[]);
a.filter('alfa', function(){} );
a.controller('userController', function(myFilterFilter) {
});
If you try, you'll see that DI handles alfaFilter in the first controller just fine. However, myFilterFilter will generates an error. (Despite a.filter("") being declared later than module x).
Note that the double Filter is intended, it's the way to insert filters into controllers, and was faster to demonstrate..

Resources