how to define normal javascript function inside the controller in angularjs - javascript

I have a code snippet below.
sample.js
(function() {
/*global angular */
'use strict';
angular.module('myapp', ['spinner'])
.controller('myCtrl', ['$scope', '$window', function ($scope, $window ) {
$scope.methodname = function() {
if(something){
/* Doing some operations */
}
};
/* Here I need to define the callme javascript function */
function callme(response){
/* If I call like this, I'm getting error in console. */
}
}]); /* Controller ends here */
/* Creating a new anonymous function to perform some operations */
(function () {
'use strict';
/* Edited */
code.util.myHTTP(url, function (response) {
// Adding response to session storage
callme(response);
}, function () {
// Removing from session storage
});
})();
}());
Here, I can't able to call callme javascript function inside angular controller . I'm getting error in console like
Uncaught ReferenceError: callme is not defined
Is there any way to achieve this?
I need to use some controller parameters like $window inside callme function, that's why I'm defining callme function inside controller.
I have run function in my js file already like below
.run(function($rootScope, $log, $window) {
});
My requirement is like call anonymous function, on load there will be some api response, I need to call one method to process the response. because of these controller parameters, I wanted to define my method inside the controller. Is there any alternate way to achieve this?

Your indentation is all over the place and is what makes this code hard to understand. Here's your correctly formatted code..
(function () {
/*global angular */
'use strict';
angular.module('myapp', ['spinner'])
.controller('myCtrl', ['$scope', '$window', function ($scope, $window) {
$scope.methodname = function () {
if (something) {
/* Doing some operations */
}
};
/* Here I need to define the callme javascript function */
function callme (response) {
/* If I call like this, I'm getting error in console. */
}
}]); /* Controller ends here */
/* Creating a new anonymous function to perform some operations */
(function () {
'use strict';
/* Edited */
code.util.myHTTP(url, function (response) {
// Adding response to session storage
callme(response);
}, function () {
// Removing from session storage
});
})();
}());
The reason this doesn't work is because function declarations are hoisted to the top of their scope, but do not exist outside of that scope. If we remove some cruft, this is what your code simplifies to:
(function() {
function MyController($scope) {
$scope.methodname = function() {}
function callme(response) {
}
}
(function() {
callme()
}())
}())
callme is hoisted, but only to the top of MyController. That symbol doesn't exist outside of that scope, and that's why you can't do callme() in your nested scope.
What you are doing seems like an anti-pattern; even if you could achieve this, core.util.myHTTP would not execute within the Angular digest cycle, so you'd have to call $scope.$apply inside of your controller, which is generally considered a bad thing. Why not just use $http instead?
Nevertheless, if you really want to do this (and you don't), you could define your function like so:
(function() {
function callme(response) { }
function MyController($scope) {}
(function() {
...
callme()
}())
}())
Alternatively you could use directives (or components, depending on your angular version) to handle this instead.. which is how it should be done.
function SpinnerCtrl($http) {
this.$http = $http
}
SpinnerCtrl.$inject = ['$http']
SpinnerCtrl.onInit = function onInit() {
var that = this
return this.$http.get(url)
.then(function (response) {
// Store it in session storage, do whatever.
// Presumably there's some data you want to make accessible to other parts of the app, so I assign it to the controller here
that.response = response
})
}
angular.module('myapp', ['spinner'])
.component('spinner', {
controller: SpinnerCtrl,
template: '<h1>{{ $ctrl.response }}</h1>'
})
// or
function SpinnerCtrl($scope, $http) {
return $http.get(url).then(function (response) {
$scope.response = response
})
}
angular.module('myapp', ['spinner'])
.directive('spinner', function () {
return {
controller: SpinnerCtrl,
template: '<h1>{{ response }}</h1>'
}
})
Note that really you should move the $http call to a service and handle the session storage in there too; the session storage thing is implementation detail and the component/directive using it should not have to care. I haven't done that just for brevity.

Related

From run block can i able to call angular scope function inside another controller instead of $rootscope

I need to call angular Scope function inside some controller from runblock. can i able to call the function or else need to use rootScope or $scope.apply.
First method:
myAPP.run(function ($rootScope, $state,$scope) {
$scope.menupage();
});
var SampleController = function ($scope,$localStorage) {
$scope.menupage =function()
{
// some logic
};
});
SampleController.$inject = ['$scope','$localStorage'];
Else need to use like this
myAPP.run(function ($rootScope, $state,$scope) {
$scope.$apply(function() {
$scope.menupage();
});
});
var SampleController = function ($scope,$localStorage) {
$scope.menupage =function()
{
// some logic
};
});
SampleController.$inject = ['$scope','$localStorage'];
myAPP.run(function ($rootScope, $state,$scope) {
You can't have $scope object as a third parameter here, because both $scope and $controller objects are created during compiling and linking phase, which follows run phase during which run blocks are executed. So you can't have them in your run blocks. Only the $rootScope is available in run blocks since it's a service and only services are available in run blocks.

How javascript select remote-data.service

I bought an app. I'm new with Javascript and AngularJS. I'm trying to following the code but I don't understand how the function on homeService.js knows that has to use remote-data.service.js
This is the home.controller.js
...
(function activate() {
...
loadCategories();
...
})();
...
// ...............................
function loadCategories() {
debugger;
homeService.getFeaturedCategories()
.then(function(categories) {
vm.categories = categories;
});
}
The function call homeService.getFeaturedCategories(). So....
home.service.js
function getFeaturedCategories() {
return dataService.getFeaturedCategories();
}
The function call to dataService.getFeaturedCategories()
Here is when data.service.js call to a remoteDataService.js and this file make the hhtp.get (I paste the full code of data.service.js):
(function() {
'use strict';
angular
.module('restaurant.common')
.factory('dataService', dataService);
dataService.$inject = ['ENV', '$injector'];
/* #ngInject */
function dataService(ENV, $injector) {
switch(ENV.dataProvider) {
case 'LOCAL':
return $injector.get('localDataService');
case 'REMOTE':
return $injector.get('remoteDataService');
case 'FIREBASE':
return $injector.get('firebaseDataService');
}
throw new Error('Data provider is not valid');
}
})();
I wanna know:
How the function returns remoteDataService.
Also I wanna know how make that only the function dataService.getFeaturedCategories() in the home.service.js make that dataservice return a localDataService. Because I wanna load a local JSON (not make a http.get)
Thanks!
Don't understand question. Your data service read ENV.dataProvider once, and return proper service. It's unable to return different services for different calls in current implementation.
you should use "localDataService" in home.service instead of "dataService". Just change names.
In your Home.service you should have lines like:
homeService.$inject = ['dataService'];
function homeService(dataService){
...
}
change it to: (order of $inject and arguments should be same.)
homeService.$inject = ['dataService', 'localDataService'];
function homeService(dataService, localDataService){
...
}
and use localDataService in your fn.

Dynamically add properties/function to a service/factory

I wrote a small Angular1 app which has a Database service that is using LokiJS.
I was wondering if there is a way to dynamically add properties/functions to a Service/Factory.
I'm trying to add dynamic getter for every collection that is created via this Service.
Here my example:
Database.js
angular.module('MyApp')
.factory('Database', ['$log', '$q', 'Loki',
function Database($log, $q, Loki)
{
var _db,
dbInitialized = false;
function init(config)
{
// some logic here
}
function addCollection(name, cfg) {
// some logic here
_db.addCollection(name, cfg);
// this doesnt work, but is desired ->
/*this['get'+name] = this.getCollection.bind(this, name);*/
}
function getCollection(collectionName) {
// some logic here
return something;
}
return {
init: init,
addCollection: addCollection,
getCollection: getCollection
};
}
]
);
app.js
angular
.module('MyApp', ['lokijs'])
.run(['Database',
function (Database) {
Database.init();
Database.addCollection("MyCollection", {});
// then fill collection, afterwards ->
var collection = Database.getCollection("MyCollection");
// I would like to use Database.getMyCollection()
}]);;
Is there a way to modify a initialized Service/Factory?
The most appropriate place for that is decorator
app.decorator('Database', ['$delegate', function ($delegate) {
var Database = $delegate;
Database.init();
Database.addCollection("MyCollection", {});
...
return Database;
}]);
The recipe doesn't really differs from run block, but it guarantees that service will be initialized on injection, while run blocks depend on their order.

Loading view configuration

I would like to do something like this:
app.config(function($routeProvider){
$routeProvider.when('products/list', {
controller: 'ProductListCtrl',
templateUrl : 'products/list/view.html',
resolve : { data : function(){
...
},
loadingTemplateUrl : 'general/loader.html'
}
});
I would like to have the loading page in a different view.
This would make the code in the view and controller of every page cleaner, (no <...ng-include ng-show="loading"...>). This would also mean that I don't have to $scope.$watch the data for changes. Is there a clean solution to do something similar (not necessarily in the .config method) or an alternative library to do this?
Assuming you want to show some general template for all state transitions while the data is resolved, my suggestion is to listen to the events fired by the routing library. This allows to use one central point to handle all state transitions instead of polluting the routing config (which I think will not be that easy to do).
Please see the docs for $routeChangeStart, $routeChangeSuccess and of course $routeChangeError at the angular router docs
Maybe someone could be interested in what I did: I created a new service and a new view directive. It could seem like a lot of work, but doing this was much easier than I had expected. The new service enables me to separate the main view from the loading view, that I could reuse in all pages of the application. I also provided the possibility to configure an error template url and error controller, for when the loading failed.
The Angular $injector, $templateRequest and $controller services do most of the work. I just had to connect a directive, that depends on these services, to the right event ($locationChangeSuccess), and to the promise, retrieved (using $q.all) from the resolve object's functions. This connection was done in the route service. The service selects the right template url and comtroller, and passes it on for the directive to handle.
A shortened version (with the getCurrentConfig method left out):
RouteService:
(function () {
'use strict';
// provider:
angular.module('pikcachu')
.provider('pikaRouteService', [function () {
var routeConfigArray;
var otherwiseRouteConfig;
//configuration methods
this.when = function (url, routeConfig){
routeConfigArray.push({url: url, routeConfig: routeConfig});
return this;
}
this.otherwise = function(routeConfig){
otherwiseRouteConfig = routeConfig;
return this;
}
// service factory:
this.$get = ['$rootScope', '$location', '$q', '$injector', '$templateRequest',
function ($rootScope, $location, $q, $injector, $templateRequest) {
function RouteService() {
this.setViewDirectiveUpdateFn = function(){ /*...*/ }
function init(){
$rootScope.$on('$locationChangeSuccess', onLocationChangeSuccess);
}
function onLocationChangeSuccess(){
// get the configuration based on the current url
// getCurrentConfig is a long function, because it involves parsing the templateUrl string parameters, so it's left out for brevity
var currentConfig = getCurrentConfig($location.url());
if(currentConfig.resolve !== undefined){
// update view directive to display loading view
viewDirectiveUpdateFn(currentConfig.loadingTemplateUrl, currentConfig.loadingController);
// resolve
var promises = [];
var resolveKeys = [];
for(var resolveKey in currentConfig.resolve){
resolveKeys.push(resolveKey);
promises.push($injector.invoke(resolve[resolveKey]));
}
$q.all(promises).then(resolveSuccess, resolveError);
function resolveSucces(resolutionArray){
// put resolve results in an object
var resolutionObject = {};
for(var i = 0; i< promises.length;++i){
resolved[resolveKeys[i]] = resolutionArray[i];
}
viewDirectiveUpdateFn(currentConfig.errorTemplateUrl, currentConfig.errorController);
}
function resolveError(){
viewDirectiveUpdateFn(currentConfig.errorTemplateUrl, currentConfig.errorController);
}
}
}
init();
}
return new RouteService();
}]
})();
View directive
(function () {
'use strict';
angular.module('pikachu')
.directive('pikaView', ['$templateRequest', '$compile', '$controller', 'pikaRouteService', function ($templateRequest, $compile, $controller, pikaRouteService) {
return function (scope, jQdirective, attrs) {
var viewScope;
function init() {
pikaRouteService.listen(updateView);
}
function updateView(templateUrl, controllerName, resolved) {
if(viewScope!== undefined){
viewScope.$destroy();
}
viewScope = scope.$new();
viewScope.resolved = resolved;
var controller = $controller(controllerName, { $scope: viewScope });
$templateRequest(templateUrl).then(onTemplateLoaded);
function onTemplateLoaded(template, newScope) {
jQdirective.empty();
var compiledTemplate = $compile(template)(newScope);
jQdirective.append(compiledTemplate);
}
}
init();
};
}
]);
})();

How do I add result to my scope ng-click?

This is a relatively simple piece of code that calls a service and returns some data. I need to set the $scope with the result of the data. Is there an easy way to set this data to the scope without resorting to to binding the scope to the function in the then clause?
Angular Code
(function () {
var app = angular.module('reports', []);
var reportService = function($http, $q) {
var service = {};
service.getMenuData = function() {
var deffered = $q.defer();
$http.get('/Report/MenuData').success(function(data) {
deffered.resolve(data);
}).error(function(data) {
deferred.reject("Error getting data");
});
return deffered.promise;
}
return service;
};
reportService.$inject = ['$http', '$q'];
app.factory('reportService', reportService);
var reportMenuController =
function ($scope, $http, reportService) {
$scope.getMenuData = function(e) {
reportService.getMenuData().then(function(data) {
// Need to set the $scope in here
// However, the '$scope' is out of scope
});
}
};
reportMenuController.$inject = ['$scope', '$http', 'reportService'];
app.controller('ReportMenuController', reportMenuController);
})();
Markup
<div>
<div ng-controller="ReportMenuController">
<button ng-click="getMenuData()">Load Data</button>
</div>
</div>
There is absolutely no problem to set the $scope from within the function passed to then(). The variable is available from the enclosing scope and you can set your menu data to one of its fields.
By the way: You should consider to use then() instead of success() for your http request. The code looks much nicer because then() returns a promise:
service.getMenuData = function() {
return $http.get('/Report/MenuData').then(function(response) {
return response.data;
}, function(response) {
deferred.reject("Error getting data");
});
}
success() is deprecated by now.
I didn't notice the small detail missing in the plunker where my code was different.
(function () {
...
var reportMenuController =
function ($scope, $http, reportService) {
$scope.getMenuData = getMenuData;
function getMenuData(e) {
reportService.getMenuData().then(function(data) {
// Now I have access to $scope
});
}
};
...
})();
Notice the changes to the two lines as below:
$scope.getMenuData = getMenuData;
function getMenuData(e) {
This also begs a small question which is, "Why is it okay to set getMenuData to the $scope before it is declared?

Categories

Resources