I am new to Angular. I have a simple web page, but the codes for controller are not working. It seems I do not call or inject service "ListLogsFactory" in the controller properly. Please help. Thank you.
My codes include a module, service, and controller that all declared/defined as follows:
var myApp = angular.module("ListLogsModule", []);
myApp.factory('ListLogsFactory', function ($http) {
var thisPageNumber = 1;
var thisPageSize = 10;
var baseUrl = '../Api/LogApi/GetLogsByPage';
var items = {};
$http({
method: 'GET',
url: baseUrl,
data: $.param({ pageNumber: thisPageNumber, pageSize: thisPageSize })
})
.success(function (data, status, headers, config) {
items = data;
console.log(items);
})
.error(function (data, status, headers, config) {
alert('error: ' + status);
});
function getData() {
return items;
}
});
// The error is seen in FireFox and happens in the controller code:
myApp.controllers.ListLogsController = function ($scope, ListLogsFactory) {
$scope.logs = ListLogsFactory.getData(); // NOTE: this line throws error on running with something like "ListLogsFactory" is undefined
}
When you use factory you have to return something. You're just defining a bunch of methods there but they aren't available to anybody.
It's also good to use a different naming convention. For example, instead of LogsController, use LogsCtrl. AngularJS appends "Controller" internally and you might end up, in exotic situations, handling names like "LogsControllerController".
A simplified approach of using factory and returning the service:
var ListLogsModule = angular.module("myApp", []);
ListLogsModule.factory('ListLogsSrv', function ($http) {
// first define the service (you're using a factory)
var getData = function() {
return "hey";//items;
};
// then return it.
// offer a public method "getData" that uses your internal getData()
return {
getData : getData
}
});
ListLogsModule.controller("ListLogsCtrl", function ($scope, ListLogsSrv) {
$scope.w = "world";
$scope.logs = ListLogsSrv.getData();
});
You also have an $http request in the factory. That means that you'll trigger the async request when you instantiate the service (when it is used for the first time), so nobody will wait for it to finish and you'll be getting undefined.
If you are using this service in a controller, you will probably need to resolve a promise.
An example of using a promise:
var promise = $q.defer();
var thisPageNumber = 1;
...
var baseUrl = '../Api/LogApi/GetLogsByPage';
...
promise = $http.get(...
Now you can use this promise in the controller, for example, or in the methods of your service.
I answered a related question two days ago Angular Service Definition: service or factory
myApp.controllers.ListLogsController = function ($scope, ListLogsFactory) {
$scope.logs = ListLogsFactory.getData();
}
should be
myApp.controller("ListLogsController", function ($scope, ListLogsFactory) {
$scope.logs = ListLogsFactory.getData();
});
The following is extended the suggestions from #Eduard Gamonal to make variables/methods of angular service or factory, so it is considered a trick to remember syntax of angular service or factory.
Trick to memorize syntax of "service" or "factory" in Angular
Service is tied with "service" key word; "this" key word to make function instance members public; and "=" to make assignments to "function instance members".
Factory is tied with "factory" key word; "return" keyword to make/return a public object; and ":" to all key/value pairs assignments.
Details.
Service deals with "variables" (or "instance members"), and to make them "public", I use the "this" keyword, and because a service deals with "variables" (or "instance members") to-be-public we use "=" after a "variable" name.
"getLogs" can be treated like a "public variable" or "instance member", and written (in "assignment" meaning) like this.getLogs = function() {...}.
And the whole service is defined with the "service" key word:
<script type="text/javascript">
var myApp = angular.module("ListLogsModule", []);
myApp.service('ListLogsService', function () {
this.getLogs = function () {
var logs = [
{"LogId":5405,"RecordedDate" : "2012-11-19T14:22:02.247", "Event" : "Log On"},
{"LogId":5416,"RecordedDate" : "2012-11-19T14:55:02.247", "Event" : "Log Out"}
];
return logs;
}
});
myApp.controller('ListLogsCtrl', function ($scope, ListLogsService) {
$scope.logs = ListLogsService.getLogs();
});
</script>
Factory deals with a returned "object" and to make them "public", I use the "return" keyword, and because a factory deals with "object" to-look-like-JSON-object I use ":" after each "property" name inside { } of the "return" statement.
"getLogs" can be treated like a property (or key) of the returned JSON object, and is written (in "key/value" pair) like getLogs : function() {...}.
And the whole factory is defined with the "factory" key word:
<script type="text/javascript">
var myApp = angular.module("ListLogsModule", []);
myApp.factory('ListLogsFactory', function () {
return {
getLogs: function () {
return[
{"LogId":5405,"RecordedDate" : "2012-11-19T14:22:02.247", "Event" : "Log On"},
{"LogId":5416,"RecordedDate" : "2012-11-19T14:55:02.247", "Event" : "Log Out"}
];
}
}
});
myApp.controller('ListLogsCtrl', function ($scope, ListLogsFactory) {
$scope.logs = ListLogsFactory.getLogs();
});
</script>
In summary: To memorize syntax of "service" or "factory" in Angular
Service is tied with "service" key word; "this" key word to make function instance members public; and "=" to make assignments to "function instance members".
Factory is tied with "factory" key word; "return" keyword to make/return a public object; and ":" to all key/value pairs assignments.
Related
Pardon if this question is a total blow-off... Just getting warmed-up into the world angularJS.
I have these two controllers: seekerController and wizardController...
Inside the wizardController, I have a chat Scope object, and I have implemented a bunch of functions that are manipulating this chat Scope object.
Going back to the other controller now, ( seekerController ), I discover that I need to have basically a direct replica of this chat Scope object and all the other functions manipulating it as I have inside wizardController
The obvious way is just to copy all these into my other controller, and my work is done under a minute, but then I'll have a lot of repeated stuffs everywhere...
So: I'm looking for a way where I can have this(the code) in a single place, but still be able to have access to this chat Scope object from both controllers, as well as all the other functions working seamlessly.
Update - add code samples:
//seekerController
angular.module('cg.seeker', [])
.controller('SeekerController', ['$scope', 'seekerService', 'timeService', 'chatService', '$stateParams', 'toastr',
function ($scope, seekerService, timeService, chatService, $stateParams, toastr) {
...
// THE CHAT BUSINESS
$scope.chat = { close: true };
chatService.unreadCount(function(count){
$scope.chat.unreadCount = count;
$scope.$apply();
});
chatService.listDialogs( function (dialogList) {
$scope.chat.dialogList = dialogList.items;
$scope.$apply();
} );
$scope.endChat = function () {
$scope.chat.close = true;
}
$scope.chatBox = function (dialogId, occupants_ids) {
$scope.chat.opponentId = getOpponentId(occupants_ids);
chatService.getMessages( dialogId, function (messageList) {
$scope.chat.messages = messageList.items;
$scope.chat.close = false;
$scope.$apply();
});
}
var getOpponentId = function (opponentId) {
if(typeof(opponentId) != 'object') {
return opponentId;
} else {
return opponentId.filter(function(x) { return x != $scope.seeker.chat_user.chat_id_string; })[0];
}
}
$scope.sendMsg = function (opponentId) {
var msg = {
type: 'chat',
body: $scope.chat.msg,
extension: {
save_to_history: 1,
}
};
chatService.sendMsg(opponentId, msg);
$scope.chat.msg = '';
}
...
I now have an exact replica of the above code in a second controller WizardController. Exactly same, with no changes... and even a third controller have some of these, though not all.
The next level of abstraction to angularjs controllers are
Factory
Service
Provider
You could use a service called maybe chatService which could contain the common code. You can inject the service into any controller which needs the common functionality and invoke the methods on the Service.
Do note that you could use any of the above three options even though I have mentioned just Service in the above statement.
EDIT 1:
You could move the common parts of the code from Controller to Service.
For example:- You could move the construction of msg object from controller to chatService. You controller would be simply -
$scope.sendMsg = function (opponentId) {
chatService.sendMsg(opponentId);
$scope.chat.msg = '';
}
And your chatService would be doing the hard-work.
$chatService.sendMsg = function (opponentId) {
var msg = {
type: 'chat',
body: $scope.chat.msg,
extension: {
save_to_history: 1,
}
};
sendMsg(opponentId, msg);
}
After simplifying the Controllers you could revisit to see if you could use only one controller instead of 3 as they seem to be doing similar function.
I have two controllers: Controller1 and Controller2
In Controller1's $scope, I have set up all my values I need. Using the data in $scope, I'm trying to run certain functions and pass the return values to Controller2.
I was thinking about making a factory to pass variable from Controller1 to Controller2. However, I realized all input values I need lives in Controller 1. I wonder whether factory can persist the data when it runs in Controller1 and return that data when it runs again in Controller2.
Thanks
Factory is a singleton so it can be used to share data among different controllers or directives. Take a look at the fiddler here. I have created a factory 'sharedContext' which can be used to share any key-value pair across controllers using different $scope.
Factory
myApp.factory("sharedContext", function() {
var context = [];
var addData = function(key, value) {
var data = {
key: key,
value: value
};
context.push(data);
}
var getData = function(key) {
var data = _.find(context, {
key: key
});
return data;
}
return {
addData: addData,
getData: getData
}
});
From the controller that needs to share the object can call the 'addData' method of the factory to store the data under a key. The other controllers/directives which are interested in accessing the shared data can do so by calling the 'getData' method and passing the correct key.
Controller (Sharing Data)
function MyCtrl_1($scope, sharedContext) {
$scope.input_1 = 5;
$scope.input_2 = 15;
$scope.add = function() {
$scope.result = $scope.input_1 + $scope.input_2;
sharedContext.addData("Result", $scope.result)
}
}
Controller (accessing shared data)
function MyCtrl_2($scope, sharedContext) {
$scope.getData = function() {
$scope.result = sharedContext.getData("Result").value;
}
}
The only assumption here is that both the controllers need to use the exact key to share the data. To streamline the process you can use a constant provider to share the keys. Also note that I have used underscore.js to look for the key in the shared context dictionary.
This is the simplest solution that you can come up with. As you can see the factory is a simple object and because of that construct it's passed by reference not by value that means in both controller dataFactory is the same
http://plnkr.co/edit/eB4g4SZyfcJrCQzqIieD?p=preview
var app = angular.module('plunker', []);
app.controller('ControllerOne', function (dataFactory) {
this.formFields = dataFactory
});
app.controller('ControllerTwo', function (dataFactory) {
this.formData = dataFactory
});
app.factory('dataFactory', function () {
return {};
})
edit
app.factory('dataFactory', function () {
var factory = {
method1: function (arg) {
console.log('method1: ', arg)
factory.method2('called from method1')
},
method2: function (arg) {
console.log('method2: ', arg)
}
}
return factory;
})
I have set up two controllers (Controller A and Controller B) and a service (Service). I am attempting to sync the data from controller A to the service, and present that information to Controller B.
Within my Service, I've established a variable confirmdata and get and set functions:
function setData(data) {
confirmdata = angular.copy(data);
}
function getData() {
return confirmdata;
}
In controller A I've created a function syncto sync information from the controller to the service:
this.sync = function () {
var data = {
payment: this.getpayment()
}
Service.setData(data);
In controller B I've assigned a function as:
this.sync = function () {
this.viewData = Service.getData();
console.log('TestingData', this.viewData);
For a reason I am unaware of; my console log simply returns undefined when it should be returning the results of the getpayment() function. Am I missing something here?
The fact that you are getting undefined would indicate that you haven't initialized 'confirmdata' in your service. Whether this is the actual issue though, isn't clear. For a simple example, I would design your service like this:
myApp.factory('sharedService', [function () {
var confirmdata = {};
return {
setData: function (newData) { confirmdata = newData; },
getData: function getData() { return confirmdata; }
}
}]);
Take a look at this plunker. It gives an example of data being shared between controllers via a service.
--- Given this code in a file ---
angular.module('storyCtrl', ['storyService'])
.controller('StoryController', function(Story, socketio) {
var vm = this;
Story.getStory()
.success(function(data) {
vm.stories = data;
});
vm.createStory = function() {
vm.message = '';
var newMessage = vm.storyData.content;
var newStory = { str: newMessage , timeNow: new Date(), mess: "Hello" };
Story.createStory(newStory)
.success(function(data) {
vm.storyData = '';
vm.message = data.message;
});
};
socketio.on('story', function(data) {
vm.stories.push(data);
})
})
Where does "data" being initialize or where is it coming from as it is not even a global variable or from ['storyService'].
Thank you
The variable data represents what the function (getStory or createStory or the on function) is returning to you for use in the function. For example, the getStory function might be returning a json array. Within the success function, this data is assigned to the vm.stories variable.
Does that help?
The storyCtrl module references another module called storyService. Slightly confusing, the storyService module contains a service (or factory) called Story. The Story service provides a method called getStory. Internally getStory very likely makes a call using $http. You can tell because getStory does not use standard promises, but instead uses the success and error methods that $http provides.
I am new to angularjs and so i was going through the basic examples i found online initially just to understand the working and concepts used. When i encountered the concept of "factory service creation" (which is a way to expose data from server to views in and angularjs), i found it difficult to understand the flow between the service's function arguments and the calls made to it .
`<html ng-app="countryApp">
<head>
<meta charset="utf-8">
<title>Angular.js Example</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular-route.min.js"></script>
<script>
var countryApp = angular.module('countryApp', ['ngRoute']);
countryApp.config(function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'country-list.html',
controller: 'CountryListCtrl'
}).
when('/:countryName', {
templateUrl: 'country-detail.html',
controller: 'CountryDetailCtrl'
}).
otherwise({
redirectTo: '/'
});
});
countryApp.factory('countries', function($http){
return {
list: function(callback){
$http.get('countries.json').success(callback);
},
find: function(name, callback){
$http.get('countries.json').success(function(data) {
var country = data.filter(function(entry){
return entry.name === name;
})[0];
callback(country);
});
}
};
});
countryApp.controller('CountryListCtrl', function ($scope, countries){
countries.list(function(countries) {
$scope.countries = countries;
});
});
countryApp.controller('CountryDetailCtrl', function ($scope, $routeParams, countries){
countries.find($routeParams.countryName, function(country) {
$scope.country = country;
});
});
</script>
</head>
<body>
<div ng-view></div>
</body>
</html>`
so in the code i ve posted, can anyone let me know or explain the flow between the "factory's list and find methods( keeping the callback argument particularly in mind)?
i am not able to understand why the same factory method is called again by itself( callback argument)
please help me out..
Regarding the list function
When the CountryListCtrl controller is instantiated, the countries service (which is an object) is being passed as an argument.
Then the countries.list function (defined within countries service obviously) is being called and passed a callback function.
The countries.list function makes a GET request, and if successful (i.e. the $http promise is resolved with success), the anonymous callback function, that was passed in when the function was called in the CountryListController controller is called and the $http service passes the returned data as an argument - Which the anonymous function then assigns to the $scope.countries property.
The countries.find function is the same basic pattern, with the difference that $routeParams is picking up the /:countryName from the route, and passing it into the countries.find function as an argument for the purpose (it seems) of picking out a specific country from the response data returned by the server and then assigning it to the $scope.country property.
the portion of code i am commenting on is
countryApp.factory('countries', function($http){
return {
list: function(callback){
$http.get('countries.json').success(callback);
},
find: function(name, callback){
$http.get('countries.json').success(function(data) {
var country = data.filter(function(entry){
return entry.name === name;
})[0];
callback(country);
});
}
};
});
Here the factory is returning an object with two functions namely list and find.
both the function has a parameter called callback. callback is basically the function that you want to call when the service is executed successfully. As both list and find are going to make Asynchronous calls to server, you would want to be notified when the call is done.
Angular however has a neater way of doing this, called promise. and if we implement promise api the code becomes
countryApp.factory('countries', function($http, $q){
return {
list: function(){
var defered = $q.defer();
$http.get('countries.json').success(function(result){
defered.resolve(result);
})
.error(function(error){
defered.reject(error)
})
return defer.promise
},
find: function(name){
var defered = $q.defer();
$http.get('countries.json').success(function(data) {
var country = data.filter(function(entry){
return entry.name === name;
})[0];
defered.resolve(country);
})
.error(function(error){
defered.reject(error)
})
return defer.promise;
}
};
});
Angulars promise api is very well documented here
https://docs.angularjs.org/api/ng/service/$q
in short what it says is promise object is a contract that when an asynchronous work is completed then it would either be resolved() (completed successfully) or rejected (completed unsuccessfully) and promise objects then function would be called.
then(success(), error())
your controller would become.
countryApp.controller('CountryListCtrl', function ($scope, countries){
countries.list().then(function(countries) {
$scope.countries = countries;
});
}, function(error){
console.log("unable to fetch the list of countries : " + error)
});
countryApp.controller('CountryDetailCtrl', function ($scope, $routeParams, countries){
countries.find($routeParams.countryName).then(function(country) {
$scope.country = country;
}, function(error){
console.log("unable to find the country: " + error)
}));
Hope it helped you.
first of all we are defining modules for any application in angularJS.
then we are defining configuration for the module where inside [] we are keeping all required dependency.we can define our own angular directive which will connect java controller to get value in respective format like json etc.Then while defining angular controller we can invoke our defined directive in our angular controller to make availability for data, and from angular controller we can get value to angular view which will display in html or any view page.