Returning function from AngularJS factory - javascript

I'm trying to understand what the purpose is of the return part of this AngularJS factory method means?
return {
getMessages: getMessages
};
What happens if we added a new method to this factory called getAnotherMessage(), would we need to update this return segment?
myModule.factory('HelloWorld', function($q, $timeout) {
var getMessages = function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve(['Hello', 'world!']);
}, 2000);
return deferred.promise;
};
return {
getMessages: getMessages
};
});

factory is a provider constructor:
factory(fn) - registers a service factory function, fn, that will be
wrapped in a service provider object, whose $get property will contain
the given factory function.
Thus when the factory is first loaded by Angular it executes the function that's passed in and stores whatever is returned as the provider.
In other words, the following is run once, and only once- during bootstrapping:
var getMessages = function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve(['Hello', 'world!']);
}, 2000);
return deferred.promise;
};
return {
getMessages: getMessages
};
The above gets a reference to the getMessage function and attaches it to the property getMessages inside the returned singleton object.
When the provider is then injected into your code, that returned object is what is passed in giving you access to the HelloWorld.getMessages function (and any other properties in the returned object).
So, yes, if you want to associate another property, such as a function, with the provider (that the factory constructs) you need to include it as a property of the returned singleton object:
return {
getAnotherMessage: function() { ... },
getMessages: getMessages
};

You can also declare an empty object first and add functions into the object
and finally return the object.
myModule.factory('HelloWorld', function($q, $timeout) {
var myobject = {};
myobject.getMessages = function() { ... };
myobject.getAnotherMessages = function() { ... };
return myobject;
});

Related

Executing second controller's "this" in first controller through angular service

I have two controllers and a service, i am executing first controller "self/this" in the second controller. I wanted to know is this an antipattern or are there any chances of memory leak?
SelfService -- this service stores "this" of controllers in selfContainer Object.
The setSelf method takes two parameters -- name of the this/self controller and this/self itself. -- it stores them as key value pair in selfContainer Object.
The executeWithSelf method also takes two parameters -- name of the this/self and a callback. the callback is executed with the this/self as parameter.
angular.module('app')
.factory('SelfService', function () {
var selfContainer = {};
function setSelf (selfname , self) {
selfContainer[selfname] = self;
}
function executeWithSelf (selfname, callback) {
callback(selfContainer[selfname]);
}
return {
setSelf: setSelf,
executeWithSelf: executeWithSelf
};
});
FirstController
angular.module('app').controller('FirstController', function(QueryService){
var self = this;
self.counter = 0;
QueryService.setSelf('FirstController', self);
})
Second Controller
angular.module('app').controller('SecondController', function(QueryService){
var self = this;
//execute QueryService.executeWithSelf on any event and only after first controller has loaded
QueryService.executeWithSelf('FirstController', function(firstcontrollerself){
firstcontrollerself.counter++;
});
})

What is the meaning of enforce parameter in AngularJS Factory

I was going through the details of how angular actually creates factory just by using module.factory() method.
I found that internally angular uses following method which internally uses provider only
function factory(name, factoryFn, enforce)
So my question is regarding the third parameter enforce of this function ,what it actually does.
When creating an Angular service or factory, behind the scenes, Angular eventually uses the same function for both:
function factory(name, factoryFn, enforce) {
return provider(name, {
$get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
});
}
When creating a service, a return value is generally not sent, and behind the scenes, Object.create() is called to create an object containing the sayHello method.
app.service('MyService', function () {
this.sayHello = function () {
console.log('hello');
};
});
However, when creating a factory, an object literal is returned:
app.factory('MyService', function () {
return {
sayHello: function () {
console.log('hello');
};
}
});
Basically, enforce is used to enforce a return value. It's not just a question of "Is this a service or factory?" since you can still return an object literal from a service if you wanted to:
app.service('MyService', function () {
return {
sayHello: function () {
console.log('hello');
};
}
});
Regarding the question: "Which should you use?" check out this:
http://blog.thoughtram.io/angular/2015/07/07/service-vs-factory-once-and-for-all.html

http.jsonp and callbacks in javascript

I am working on a calculator that will consider AWS instance costs. I am pulling the data from a .js file on amazon and I would like to read it into an object but i keep getting an error "Uncaught ReferenceError: callback is not defined" .. here is my .js file.
(function() {
var app = angular.module('formExample', []);
var ExampleController = function($scope, $http) {
$scope.master = {};
$scope.update = function(user) {
$scope.master = angular.copy(user);
$scope.GetAws();
};
$scope.reset = function() {
$scope.user = "";
};
function callback(data) {
$scope.aws = data;
}
$scope.GetAws = function() {
var url = "http://a0.awsstatic.com/pricing/1/ec2/linux-od.min.js?callback=callback";
$http.jsonp(url);
};
$scope.reset();
};
app.controller('ExampleController', ['$scope', '$http', ExampleController]);
}());
It is weird that the aws link you are using supports jsonp but it does not take custom callback function name. (Atleast you can look up to find out if the query string they are looking for is callback or not). angular handles it when we provide callback=JSON_CALLBACK it gets translated to angular.callbacks_x which are exposed globally temporarily by angular to handle the request and resolve the promise accordingly. But for this the endpoint must take the callback argument and wrap the response in the same string and function invocation. However this endpoint does not seem to consider it and even without any callback it automatically wraps into default callback function invocation. So you would need to inject $window (Correct DI way) object and set callback function to it and ?callback=callback is irrelevant.
var ExampleController = function($scope, $http, $window) {
$scope.master = {};
//....
$window.callback = function(data) {
$scope.aws = data;
}
$scope.GetAws = function() {
var url = "http://a0.awsstatic.com/pricing/1/ec2/linux-od.min.js?callback=callback";
$http.jsonp(url);
};
$scope.reset();
};
app.controller('ExampleController', ['$scope', '$http', '$window', ExampleController]);
Plnkr
It is because the AWS script is looking to call a function called "callback" on the global scope (outside of Angular). Since your function is within the scope of another (IIFE) function, it cannot be accessed.
What I've done in a case like this is simply put the function in the global scope.
In cases where an application requires some API to have loaded before Angular can do it's magic and has a callback similar to your situation, I have done the following, manually bootstrapping Angular:
index.html
<script src="http://www.example.com/api?callback=myCallbackFunction"></script>
app.js
// callback function, in global (window) scope
function myCallbackFunction() {
// manually bootstrap Angular
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
}
// your IIFE
(function() {
})();
Notice callback should be set in window scope.
So,one solution is like:
$scope.reset = function() {
$scope.user = "";
};
window.callback = function(data) {
$scope.aws = data;
}
$scope.GetAws = function() {
var url = "http://a0.awsstatic.com/pricing/1/ec2/linux-od.min.js?callback=callback";
$http.jsonp(url);
};

JavaScript service: how to provide a () method, like an object constructor?

I would like to create a service that will create an interface to AngularJS's $http based on this. I would like to use dependency injection to inject the service without re-writing individual function calls and keeping the code clean. To do this I am providing a common service that creates a variable to the $http object like this:
commonService = function(...) {
return {
...
$http: $http
}
Then I use common.$http everywhere in the code. To change $http from AngularJS $http to my httpService, I need to only change it in one place. httpService looks like this:
function httpService($http, $q, pendingRequests, $interval) {
var get = function(url) {
...
return requestPromise;
};
var service = {
get:get
};
return service;
}
This works for calls to $http.get() but what about calls to $http({method:'get', url:'...'}); ?
Is it possible to provide the () method, which is really httpService()()? Otherwise it would call the AngularJs method httpService().
You can just return a function instead of an object. You can add the properties to your function
function httpService($http, $q, pendingRequests, $interval) {
var get = function(url) {
...
return requestPromise;
};
// Instead of returning an object, return a function
var service = function() {
// do whatever you want here
};
service.get = get;
// Add more properties to service as needed
return service;
}

accessing object properties with object method

I am trying to build an application called myApp which has the property regularNameErrors and the Method populateJSON which uses an AJAX call to get a JSON object which is then added to the property declared as one of the arguments to the method.
The function to get the data definitely works because the alert at position 3 gives the correct list of keys. however the alert at 1 returns undefined and the alert at 2 blank.
When I replace the line destination = data with myApp.regularNameErrors = data again it works so I assume that I have misunderstood how to pass object properties to object methods. However I want to use the method populateJSON several times and need to know the correct way to pass it properties.
var myApp = {
init: function () {
myApp.populateJSON(myApp.regularNameErrors, 'data/spelling.json').done(function () {
alert(myApp.regularNameErrors['kingscross']); //1
});
},
regularNameErrors: {}, //Object of spelling mistake:proper key:value pairs
populateJSON: function (destination, source) {
var def = $.Deferred();
$.getJSON(source, function (data) {
destination = data;
alert(Object.keys(myApp.regularNameErrors)); //2
alert(Object.keys(data)); //3
def.resolve();
});
return def.promise();
},
};
With the ability to use the deferred properties of the returned getJSON object the functions can be reduced to a few lines such that it is not necessary to create a new function called populateJSON
var myApp = {
init: function () {
$.getJSON('data/spelling.json').done(function(data) {
myApp.regularNameErrors = data;
});
},
regularNameErrors: {},
};
destination is no "pointer" to the property that you passed into the function, but a variable holding the value which the property evaluated to. When you assign to destination, you just write to the local variable of your populateJSON function.
If you want to be able to declare the destination, you would need to pass a base object (or always use myApp) and a property name:
var myApp = {
init: function () {
myApp.populateJSON('regularNameErrors', 'data/spelling.json', function() {
alert(Object.keys(myApp.regularNameErrors)); //2
alert(myApp.regularNameErrors['kingscross']); //1
});
},
regularNameErrors: {}, //Object of spelling mistake:proper key:value pairs
populateJSON: function (destinationName, source, callback) {
$.getJSON(source, function (data) {
myApp[destinationName] = data;
alert(Object.keys(data)); //3
callback();
});
}
};
However, I see you are using the promise pattern. A promise should not be used as a simple notifier ("now the data has arrived somewhere"), but it should represent the data itself ("now, here's the data") - resolve it with the data instead of storing the data in a global variable/property and resolving with nothing. Actually, the $.ajax does already return such a promise so you don't have to do much for it:
var myApp = {
init: function () {
myApp.regularNameErrors = $.getJSON('data/spelling.json');
myApp.regularNameErrors.done(function(data) {
alert(Object.keys(data)); //3
alert(data['kingscross']); //1
});
}
};

Categories

Resources