I know some javascript function declarations. Like exression function, anonymous function, but I do not understand what kind of syntax of these two functions? Can anybody tell me what is the name of these two functions? I mean "manipulateData: function (input)" and "getDataById: function (id)".
Why return statement can have this syntax to return two functions? Why not return one function in one time instead of two functions? It will be great if you can give me some reference documents? Thanks.
app.service('MyService', function ($http, $q, $angularCacheFactory) {
var _dataCache = $angularCacheFactory('dataCache', {
maxAge: 3600000 // items expire after an hour
});
/**
* #class MyService
*/
return {
manipulateData: function (input) {
var output;
// do something with the data
return output;
},
getDataById: function (id) {
var deferred = $q.defer();
if (_dataCache.get(id)) {
deferred.resolve(_dataCache.get(id));
} else {
// Get the data from the server and populate cache
}
return deferred.promise;
}
};
});
These functions are just anonymous functions that happen to be values in an object. Consider this:
var object = {
add: function(x, y) {
return x + y;
}
};
object.add(1, 2); // = 3
This is the same as:
function addFunction(x, y) {
return x + y;
}
var object = {
add: addFunction
};
object.add(1, 2); // = 3
There's nothing special about these functions, as they're just normal properties of an object.
You are not returning a function in this case but an Object.
When you define a service in angularjs you have to provide its implementation in the callback (the second argument of app.service)
This callback has to return methods you want to make available to other parts of your application.
Then in a controller or in another service you will be able to write:
app.controller("MyCtrl", ["MyService", function(MyService) {
MyService.getDataById('an id');
}]);
Angular Service returns an instance of the service you bind to the app namespace, those functions in the return statement are public methods that can be worked with. Basically an Object that contains two methods manipulateData, and getDataById.
It's similar to this
function company() {
let product; // This is private
// Public Methods
return {
setLatestProduct: function(value) {
product = value;
console.log(product, ' set');
},
getLatestProduct: function() {
return product;
}
}
}
const apple = company();
console.log(apple); // { setLatestProduct: function, getLatestProduct: function }
Related
I need to return an object of methods after making a call to the IndexedDB library like so.
.factory('presentationData', ['$indexedDB', 'uuid4','$q', function ($indexedDB, uuid4, $q) {
var objectStore = $indexedDB.openStore('presentations', function(store) {
return store;
});
return objectStore.then(function(objectStore) {
var functions = getDefaultDataServiceFunctions(objectStore);
functions.getAll = function (includeFlaggedForDelete) {
if (includeFlaggedForDelete) {
return objectStore.getAll();
}
return objectStore.getAll().then(function (presentations) {
return presentations.filter(function (p) {
return !(p.meta && p.meta.localStatus === 'deleted');
});
});
};
functions.getWithLocalStatus = function (status) {
var query = $indexedDB.queryBuilder().$index('localStatus').$eq(status).compile();
return objectStore.each(query);
};
return functions;
})
}])
Why does this not return an object of methods? I don't understand!!
Using this: https://github.com/bramski/angular-indexedDB
Thanks!
This is not going to work as returning the store object is ineffective. The store will be closed and operations on it will fail.
It's really unclear to me what you are actually trying to do. Just get the data? You need to return a promise which will return the data.
.service('dataFetcher', ['$indexedDB', 'uuid4','$q', function ($indexedDB, uuid4, $q) {
this.getData = function() {
promise = $q.defer();
$indexedDB.openStore('presentations', function (store) {
... do what is needed to get the answer here...
promise.resolve(data);
}
return promise.promise;
}
}
Using this service then goes something like...
.controller('MyControl', ['dataFetcher', function ($scope, dataFetcher) {
dataFetcher.getData().then( function (data) {
$scope.data = data;
});
}];
That will give you what you in fact seek. indexed-DB works on a callback mechanism. You need to use that to design your data service in a sensible way.
I am trying to achieve a chainable object, but cannot figure out how I can do this within a function.
This is how I would like it to work:
$donate.ga('testing').go(value);
My object currently looks like this:
var $donate = {
ga: function (value) {
}
};
You simply need to make each function to return the instance of the object:
var $donate = {
ga: function (value) {
// logic
return this;
}
};
It's already solved here. You must simply return the object in your function.
You need to return the Object like that:
var $donate = {
ga: function (value) {
//after some computation
return this;
},
go: function(val) {
//after some computation
return this;
}
};
If you don't return this (this is a reference to the current Object), you either return undefined or something else and your method defined in your Object is simply out of scope (unknown).
you have to return this; in each sub function before closing it.
for example
Your code
var $donate = {
ga: function (value) {
//perform your code here
return this; // <--- Dont forget to use this before closing the function nest
},
go: function(val) {
//perform your code here
return this; // <--- Dont forget to use this before closing the function nest
}
};
I'm calling this factory function in Angular, passing in a percentage value as a parameter:
if(scroll_factory.fetch(50)) {
// If the user has scrolled 50% of page height, do something.
};
scroll_factory.$inject = ['$window', '$document'];
function scroll_factory($window, $document) {
var factory = {
fetch: fetch,
fetch_position: fetch_position
}
return factory;
function fetch(percent) {
$document.on('scroll', fetch_position)
function fetch_position() {
var window_inner_height = $window.innerHeight;
var y = pageYOffset;
var percentage = (y / window_inner_height) * 100;
if (percentage > percent) {
// Condition true - return true for the outer fetch.
}
}
return false;
}
What I want is for the fetch function to return true when the scroll condition is true. Thanks.
Your approach will not work. In:
if(scroll_factory.fetch(50)) { ... }
you are already evaluating (the function returns a value a this point) the fetch function.
You need to rethink that the fetch_position callback is continuously evaluated.
You want to have a scroll-spy functionality as a separated module?
.factory('ScrollSpy', function($document, $window) {
return function(callback) {
$document.on('scroll', function(e) {
var y = ...
if ( y > 123)
callback(y);
})
};
})
One way to solve this is to provide a factory which accepts a callback which can be evaluated depending on your demands.
I made a small example, hope it helps: http://plnkr.co/edit/du3dpMlaKYZFuy8WA0QL?p=preview
I have this in my AngularJS application:
$scope.user = {
numberValue: null
}
and I have this function that returns a value:
$scope.formalTrainingCosts = function () {
return $scope.user.avePaynonTrainedEmployees * $scope.user.newEmployeeFormalTrainingHours;
}
Can I save that value to the variable numberValue like so $scope.user.numberValue = $scope.formalTrainingCosts? If that does not work, what else can I do to get the function saved to the variable?
the answer by Blackhole will work but you can also put the function straight into the object. The downside to that would be that the function would be called every time you referenced that variable whereas Blackhole's answer would call the function once and save the answer.
$scope.user = {
numberValue: function() {
return $scope.user.avePaynonTrainedEmployees * $scope.user.newEmployeeFormalTrainingHours;
}
}
or
$scope.user = {
numberValue: $scope.formalTrainingCosts()
}
For a project I'm working on, I'm building some data objects with the following lay-out (it's a binary file that I'm reading with ArrayBuffers:
AFile.prototype = {
p: new BufferPack(),
filedata: null,
position: 0,
label_records: null,
closestmultipleof: function(n,v) {
return Math.ceil((v / n) * n);
},
r: function(size) {
result = new Uint8Array(this.filedata,this.position,size);
this.position += size;
return result;
}
readValueLabel: function() {
return {
value: this.rS(8),
len: this.rS8(),
label: this.rS(this.closestmultipleof(8, this.len + 1))
};
},
readLabelRecords: function() {
return {
rec_type: this.rS32(),
label_count: this.rS32(),
value_labels: _.map(_.range(this.label_count), function(num) {
console.debug(num);
},this)
};
},
loadFile: function(blob) {
this.filedata = blob;
this.label_records = this.readLabelRecords();
}
};
However, I seem to have problems with accessing the values in the return scope. In some return scopes, I need to access the variables from the same scope in order to manipulate the data a little bit (see the definition of value_labels).
Only, it doesn't seem to be able to access the variable label_count there (probably because it is in the same return scope). How would I be able to do this?
The only way that I can get it to work is if I do this:
ret = {}
ret['a'] = 5;
ret['b'] = ret['a'] * 2
return ret;
But that seems ugly enough. Any ideas?
And yes, it is a singleton! I'm only going to use this once.
Let me make clear: The problem is within the following code:
return {
a: functionreturn(),
b: this.a * s
};
This.a doesn't seem to exist there.
[update]
You can create a closure to label_count.
function AFile(){};
AFile.prototype ={
readLabelRecords: function() {
label_count=this.rS32();
return {
label_count:label_count,
log:console.log(label_count)//'return from rs32'
};
},
};
AFile.prototype.rS32=function(){
return "return from rs32";
}
var o = new AFile();
o.readLabelRecords();
That answer was based on the code provided, the simplest code to re produce:
function complicatedCalculations(){
return 22;
}
function returnObject(){
var cacheComplicated=complicatedCalculations();//closure variable will
// be available within the entire body of returnObject function
// but never outside of it.
return{
calculated:cacheComplicated,
twiceCalculated:cacheComplicated*2//you could not access calculated
// here so using a cache closure variable
}
}
Or have your returnObject function return a new instance of an object created with a constructor function:
function returnObject(){
return new (function(){
this.calculated=complicatedCalculations();
this.twiceCalculated=this.calculated*2;
})();
}
You forgot a comma before readValueLabel which makes the structure is invalid.
Update:
Too bad that the other answer was deleted, it had a valid point even if it didn't "compile".
Reference to this is problematic inside inner scopes in JS, but it can be worked around by doing something like that:
readLabelRecords: function() {
var that = this;
return {
rec_type: that.rS32(),
label_count: that.rS32(),
value_labels: _.map(_.range(that.label_count), function(num) {
console.debug(num);
},that)
};
}