Where should I place interface actions in Angular? - angularjs

I have problem with bootstraping my angular application. I'm wondering, where should I place interface actions? Should I create special controller or maybe a service with these actions? For example: I want to create object responsible for showing alerts and call MyUiModule.showAlert(message) from any place within app.
Which approach is better - controller, service, something else?

As you want to use the showAlert functionality from any place within the app, the best place to put it is in service.
Now in any controller, where you want to avail this service, just inject it as dependency and call the method.
app.factory("MyUiModule", function() {
var UiModule = {};
UiModule.showAlert = function(message) {
// construct the interface to show the alert
// It could be angular-ui modal window
};
return UiModule;
});
In your controller where you want to use it:
app.controller("MyController", function($scope, MyUiModule) {
$scope.login = function() {
MyUiModule.showAlert("Please enter the username");
}
});

Related

Non singleton service for angular directive

I have an angular component that is reused multiple time in the same page.
The angular component is dependent on a service, since it is reused multiple times, I would like to have a new instance of a service for each component, is that possible? Or do I have to use a for loop and create a separate object inside the service for each component to achieve the same effect?
Edit: I am using angular 1
You can create a factory (instead of a service) which returns a function to which you can even provide some data (think of it as a constructor).
angular
.module('app')
.factory('MyFactory', MyFactory);
function MyFactory() {
return (someOptions) => ({
myProperty: someOptions.myProperty,
myMethod: () => {
// ...
}
});
}
You can than use it in your controller like so. Every time you call MyFactory({ ... }) a new separate "instance" will be created.
angular
.module('app')
.controller('MyController', MyController);
function MyController(MyFactory) {
const myFactoryObj = MyFactory({ myProperty: 'test' });
}
You can use that service in each of your components as DI and then call that service to create a new instance every time. You can also set 'cache':true in your function so that you don't make multiple api calls for the same data. (Only for 'GET' method). Does that clarify your doubt?

AngularJs - Best way to include my service inside every controller?

I'm building a small two-language app with the use of angular-translate. I want to have a language switcher in every view (controller). I'm trying to figure out how to put the code responsible for language switching into every controller. The code looks like this:
var langSwitch = $Scope.setLang = function (langKey) {
$translate.use(langKey);
};
So far I've figured that I can create a factory that looks like this:
app.factory('langSwitch', function ($rootScope, $translate) {
var langSwitch = $rootScope.setLang = function (langKey) {
$translate.use(langKey);
};
return langSwitch;
});
and inject it into controllers in this maner:
app.controller('HomeCtrl', function (langSwitch) {
// normal controller code here
});
This works but 1) I'm using $rootScope and I have a feeling this is bad practice & 2) jsHint screams that "langSwitch" is not defined. Maybe there is a simpler way to make the function global without putting it into every controller?
I'm still pretty new to Angular so don't scream at me :) Thanks.
edit
My view:
<button ng-click="setLang('en_GB')">English</button>
<button ng-click="setLang('pl_PL')">Polish</button>
Although you got the idea, you overcomplicated things a bit. You could declare the service as follows:
app.service('langSwitch', function ($translate) {
this.setLang = function (langKey) {
$translate.use(langKey);
};
});
And then inject langSwitch in the controller responsible for lang switching, as you already did. No need to inject $rootScope in the service.
You don't need $rootScope indeed unless you need to process some global events in your application. All services and factories in angular are singletons by default. That means once it created, it will be passed as the same instance in every place it is declared as a dependency. So if you want to share data and functionality between different controllers - the services will suit fine. You can change your factory code to:
app.factory('langSwitch', function($translate) {
return {
setLang: function(langKey) {
$trasnlate.use(langKey);
};
};
});

Call Angular directive controller method from another controller

I have a directive which is associated with one controller and the functions in my controller defined as
MyFormController.prototype.addNewRow = function addNewRow() {
//Adding row code
};
I want to call this method from another controller, possible ways?
I ve user the service and moved the code into that service which is shared across the controllers, however the service code does the DOM manipulation, and then i guess the next question would be that can we use $compile in a service test case
service or factory is used to share data between controller.so it would be best to define function in service and factory.
demo:
(function() {
angular.module('app', [])
.service('svc', function() {
var svc = {};
svc.method = function() {
alert(1);
}
return svc;
})
.controller('ctrl', [
'$scope', 'svc', function($scope, svc) {
svc.method();
}
]);
})();
You should not!!!
That defeats the whole purpose of modularity.
If possible try to make the function generic and create a service/factory. Now both the places where you need, use the same generic function defined in service and do their stuff.
Otherwise you can also look at events to make changes accordingly.
Look at this blog post:
http://ilikekillnerds.com/2014/11/angularjs-call-controller-another-controller/
Last but the worst solution is (avoid using this, this is literally an aweful way) is catching the element inside directive and getting its scope and taking the function from it.
Example,
var otherControllerFunc = $(".inside-directive").scope().yourfunc;

AngularJS: global access to function defined in a controller

I have an angularjs app with some controllers.
At some point, I need to access a function defined inside a controller, but the place where the function is gonna be called is not inside the angularjs APP.
I'll try to build a simple scenario:
app.controller('TaskController', function ($scope, $routeParams, $window, TaskEngine, PortalUtil) {
$scope.closeTask = function() {
$scope.openTask = false;
$scope.openedTaskUrl = undefined;
}
});
-- Some other place in my web app, outside of the angular APP.
<button onclick="closeTask();">
The "closeTask()" function is never accessible, because its out of scope.
I tried to define it in the window object
$window.closeTask = function() {
$scope.openTask = false;
$scope.openedTaskUrl = undefined;
}
});
Now, my function is visible, but the variables "openTask" and "openedTaskUrl" are not.
Is it possible to do what I want?
Basically, I have a controller, and I need to access one function anywhere, to control the behaviour of a menu.
Thanks!
I would not use $window for this. Instead, Angular has a nice feature which lets not Angular code to interact with it. Using Angular.element you can access data or functions defined in Angulars Scope.
var $scope = angular.element(document.querySelector('[ng-app=app]')).scope();
$scope.$apply(function() {
$scope.print("Hello world");
});

How to call controller method from service in Angular?

I wonder if I can call controller method from service.
I know that Service is singleton and I can't inject $scope to the service.
In my case I manage Google Maps in service and want to open modal Dialog when user right clicks on Polygon.
As I know, to open/create new instance of dialog, somehow Service must notify controller to do that.
This is a template with controller + method and service: Template
var myApp = angular.module('myApp', []);
function MyCtrl($scope, gridService, $timeout) {
// how to call "foo" method from service?
$scope.foo = function(){
alert('called from service');
};
}
myApp.service('gridService', ['$timeout', function ( $timeout) {
var grid = {
fetching: false,
pristine: true,
pageType: 'Edit'
}
return {
gridSetup: function () {
return grid;
},
setGridSetup: function (newGrid) {
}
}
}]);
Thanks,
The answer is simple: you don't.
The service exists to manipulate data, nothing else. And it really shouldn't care "why" it's doing what it's doing. You ask the service to do something and wait for a response.
Personally I prefer using promises to resolve async operations (i.e. to notify the controller about a state change) since it's heavily supported by many angular services like $http.
But feel free to use callbacks of you wish.
Usually you do not need to call controller from the service - in general the single service could be used by any controller so service shall know nothing about them. In most cases controller calls to the service in react to some user's action and then you need to update view from controller somehow when service did its work (get response from server, etc.). I see following general ways how to do it.
1. Use callbacks.
//controller
$scope.onButtonClick = function() {
$scope.label = "wait, loading...";
function onSuccess(result) {
$scope.label = "done! result is " + result;
}
myService.doSomeWork(param1, param2, onSuccess);
}
//service
doSomeWork: function(param1, param2, onSuccess) {
$.get({...}, onSuccess);
}
So you provide a callback for each action.
2. Subscribe on events
You may use jQuery for events subscribing/triggering
//controller
$(myService).on('update', function() {
$scope.lastUpdateTime = new Date();
});
$scope.onButtonClick = function() {
myService.doUpdate();
}
//service
doUpdate: function() {
$.get({...}, function onOk() {
$(this).trigger('update');
});
}
3. Use promises
A lot of built-in angular services return promise objects, you may use them too:
//controller
myService.doSomething(param1).then(function(result) {
$scope.result = result;
});
//service
doSomething: function(param1) {
return $http.get({...});
}
4. Share some data
An example is $resource service - for example when you call query method it returns empty array-like object that could be safely put to scope and then fills it with values when http request is done.
//controller
$scope.options = myService.options;
$scope.onClick = function() { myService.update() }
//service
options: [],
update: function() {
var self = this;
$http.get({...}).success(function(res) {
self.options.splice(0, self.options.length); //to keep same array
self.options.push.apply(self.options, res.data.options);
});
}
In all these cases services and controllers are separated, services could be used with any controller and you may easily write unit-tests on services that will not break if you change your controller/view part somehow.
A possible solution would be to have a dialog service which you can inject into the grid service. So when the user right clicks on the polygon the handler would call open on the dialog service.
Take a look at the modal service on angular ui as an example.

Resources