Angular JS - How to call a function of a module? - javascript

I'm new to angular and have to fix bugs of my collegue. I found this factory with functions. How can I put a reset_All-function that calls the reset-function of all modules ?
.factory('MyCollection', function() {
return {
resetAll: function(projectId) {
// call the reset-function of SomeController
}
}
})
.controller('SomeController', function($scope, a) {
$scope.reset = function() {
...........
}
}

If you want to prevent tight coupling of the different modules, you can broadcast an event and catch it in the respective controllers:
.factory('MyCollection', ['$rootScope', function($rootScope) {
return {
resetAll: function(projectId) {
$rootScope.$broadcast('reset');
}
};
}]);
.controller('SomeController', ['$scope', 'a', function($scope, a) {
$scope.reset = function() {
// do something here
};
$scope.$on('reset', function() {
$scope.reset();
});
}]);
To learn about Angular's events have a look at Understanding Angular’s $scope and $rootScope event system $emit, $broadcast and $on

You need to depend on MyCollection, so you can inject it:
.controller('SomeController', [ '$scope', 'a', 'MyCollection',
function ($scope, a, MyCollection) {
$scope.reset = function(id) {
MyCollection.resetAll(id)
}
}]);
Here is the documentation to read.

Related

unable to inject a service in controller

I am using requireJS for my angularjs app.
common.service.js
define(function () {
var coreModule = angular.module('coreModule');
coreModule.config(['$provide', function ($provide) {
$provide.factory("CommonService", CommonService);
}]);
CommonService.$inject = ["$http", "$q", "$window"];
function CommonService($http, $q, $window) {
var service = {};
service.sharedValue;
return service;
}
});
page1.controller.js
define(function () {
var coreModule = angular.module('coreModule');
coreModule.controller('Page1Controller', ['$scope', "CommonService", function ($scope, CommonService) {
// Q2: common service
$scope.commonService = CommonService;
}]);
});
Now When I am running my app, it throws me below error:
Error: [$injector:unpr] Unknown provider: CommonServiceProvider <- CommonService <- Page1Controller
any inputs?
Your core module should have empty dependencies injected
var coreModule = angular.module('coreModule',[]);
Also in page1. controller you dont have to declare the module again, you can just use
angular.module('coreModule')
.controller('Page1Controller', ['$scope', "CommonService", function ($scope, CommonService) {
Define config
Define the service
Define the controller, inject the service, use the dependency in function declaration etc. As you would know, both are needed, after all you need the those handles, else what's the point in injecting.
Define a module, define module dependencies. NOTE that the service has to be defined before controller. If you reverse the order, you will get an error, probably that's what is happening here. Without full code, I can't tell.
bootstrap angular.
Finally working plunkr: http://plnkr.co/edit/CE9enkgW3KASx8pf5vdb?p=preview
define('config',[],function(){
function config($routeProvider) {
$routeProvider.when('/home', {templateUrl: 'tpl.home.html', controller: 'HomeController'})
.otherwise({redirectTo: '/home'});
}
config.$inject=['$routeProvider'];
return config;
});
define('dataSvc',[], function(app){
function factoryFunc ($q, $timeout){
var svc = {getData: getData};
return svc;
function getData() {
console.log('executing function');
var d = $q.defer();
$timeout(function(){
console.log("firing timeout");
d.resolve({name:"test", data:[1, 2, 3, 4]});
}, 750);
return d.promise;
}
}
factoryFunc.$inject=['$q', '$timeout'];
return factoryFunc;
});
define('HomeController',[], function() {
function HomeController($scope, dataSvc) {
$scope.name = "Mahesh";
dataSvc.getData().then(function(result){
$scope.data=result;
console.log($scope.data);
});
}
HomeController.$inject=['$scope','dataSvc'];
return HomeController;
});
define('coreModule', ['config', 'dataSvc', 'HomeController']
, function(config, dataSvc, HomeController){
var app = angular.module('app', ['ngRoute','ngResource']);
app.config(config);
app.factory('dataSvc',dataSvc);
app.controller('HomeController', HomeController);
});
require(['coreModule'],
function() {
angular.bootstrap(document, ['app']);
}
);
Refer also,
https://www.sitepoint.com/using-requirejs-angularjs-applications/
http://beletsky.net/2013/11/using-angular-dot-js-with-require-dot-js.html

Call function or pass data to another controller AngularJS

I already have seem other topics with this kind of issue, but no one could help me... So here is my issue:
I have a navbar with a button for search, this buttons makes and get request from a webservice and returns a json object which must be apply to fill an table list. The problem is, my button and my table are in separated controllers, and it does work like I expected.
var app = angular.module('clientRest', []).controller('lista', ['$scope', 'loadLista', function($scope, loadLista) {
$scope.contatos = loadLista.getContatos();
}]).controller('pesquisa', ['$scope', '$http', 'loadLista', function($scope, $http, loadLista) {
$scope.listar = function() {
$http.get("http://localhost/wsRest/index.php/contato").success(function(response) {
loadLista.setContatos(response);
});
};
}]).service('loadLista', function() {
var contatos = [];
return {
getContatos: function() {
return contatos;
},
setContatos: function(c) {
contatos = c;
}
};
});
My code...
When I call listar() from pesquisa controller I need to send received data to $scope.contatos from lista controller to make my ng-repeat work, everything with a single click.
How can I do it?
Thanks everyone
Better to use a service to share data between two controllers / modules as this might be the best approach. You can refer the code segment given below to understand the concept.
angular.module('app.A', [])
.service('ServiceA', function() {
this.getValue = function() {
return this.myValue;
};
this.setValue = function(newValue) {
this.myValue = newValue;
}
});
angular.module('app.B', ['app.A'])
.service('ServiceB', function(ServiceA) {
this.getValue = function() {
return ServiceA.getValue();
};
this.setValue = function() {
ServiceA.setValue('New value');
}
});
In order to trigger the data receipt event, you may use
Broadcast / emit messages - with #broadcast / #emit
An angular promise with a call back
Controller initiation function to reload the previously read information from a service
.controller('MyController', function($scope, ServiceA) {
$scope.init = function() {
$scope.myValue = ServiceA.getValue();
};
// Call the function to initialize during Controller instantiation
$scope.init();
});
Use $rootScope.$emit to emit a change event when setting the variable and use $on to get the value in the lista controller. I used customListAr here just to demostrate a button click. Does this help?
var app = angular.module('clientRest', [])
.controller('lista', ['$scope', 'loadLista', '$rootScope',
function($scope, loadLista, $rootScope) {
console.log(loadLista);
$scope.contatos = loadLista.getContatos();
$rootScope.$on('change', function() {
$scope.contatos = loadLista.getContatos();
});
}
])
.controller('pesquisa', ['$scope', '$http', 'loadLista',
function($scope, $http, loadLista) {
$scope.listar = function() {
$http.get("http://localhost/wsRest/index.php/contato").success(function(response) {
loadLista.setContatos(response);
});
};
$scope.customListAr = function() {
loadLista.setContatos(["item 1" , "item 2", "item 3"]);
}
}
])
.service('loadLista', ['$rootScope',
function($rootScope) {
var contatos = [];
return {
getContatos: function() {
return contatos;
},
setContatos: function(c) {
contatos = c;
$rootScope.$emit('change');
}
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="clientRest">
<div ng-controller="lista">
<ul>
<li ng-repeat="a in contatos">{{a}}</li>
</ul>
</div>
<div ng-controller="pesquisa">
<button ng-click="customListAr()">Click Me</button>
</div>
</div>
Your problem is that when you do $scope.contatos = loadLista.getContatos(); you are setting a static value, and angular is unable to effectively create a watcher for that object because your setContatos method is creating a new object each time. To get around this, have the controller's scope hold a reference to the parent object and then it will automatically have a watcher on that object.
var app = angular.module('clientRest', [])
.controller('lista', ['$scope', 'loadLista', function($scope, loadLista) {
$scope.contatos = loadLista.contatos;
}])
.controller('pesquisa', ['$scope', '$http', 'loadLista', function($scope, $http, loadLista) {
$scope.listar = function() {
$http.get("http://localhost/wsRest/index.php/contato"
).success(function (response) {
loadLista.contatos.data = response;
});
};
}])
.service('loadLista', function() {
var lista = {
contatos: {},
};
return lista;
});
// view:
<ul>
<li ng-repeat="contato in contatos.data">
{{ contato }}
</li>
</ul>

Angular Directive not updating after $http

I have an angular directive that looks like this:
myApp.directive('foo', function() {
return {
template: '<span>{{foo.bar}}</span>',
restrict: 'E',
scope: true,
controller: 'myController'
};
});
EDIT
I set the directive initially with this controller:
myApp.controller('myController', function ($scope, MyModel) {
$scope.foo = MyModel.get();
});
and it seems to work fine to modify the model from a second controller:
myApp.controller('myOtherController', function($scope, MyModel) {
setTimeout(function() {
MyModel.set({
bar: "biz"
});
}, 3000);
});
but not with this controller code:
myApp.controller('myOtherController', function($scope, MyModel) {
$http.get("/resource").then(function(response) {
MyModel.set(response.data);
});
});
I have confirmed that the model updates in both instances, but the directive does not update the view with the $http request.
Here is a Plunker that will give you the general idea.
I have tried all sorts of $timeout/$scope.$apply solutions and they all either do nothing or through a digest in progress error. Any help would be appreciated
When you use .then(), the data for your response is in response.data
myApp.controller('myController', function($scope, MyModel) {
$scope.foo = MyModel.get();
$http.get("/resource").then(function(response) {
MyModel.set(response.data);
});
});
The .success() method of a promise passes response.data as the first argument:
myApp.controller('myController', function($scope, MyModel) {
$scope.foo = MyModel.get();
$http.get("/resource").success(function(response) {
MyModel.set(response.data);
});
});
Also, you initialize $scope.foo = MyModel.get() when you initialize your controller, so the value of $scope.foo will be the old value after you call MyModel.set(). To fix:
myApp.controller('myController', function($scope, MyModel) {
$scope.foo = MyModel.get();
$http.get("/resource").then(function(response) {
MyModel.set(response.data);
$scope.foo = MyModel.get();
});
});
Here is a working Plunk
The only change I had to make was in the data being sent from your run function
.run(function($httpBackend) {
var res = {
bar: "It WORKED"
};
Not quite sure what the purpose of the $timeout calls is in your factory implementation, and your MyModel factory seems a bit complicated (I think there are much easier ways to accomplish what you are after).

Broadcasting across AngularJS controllers?

How do I broadcast a message between controllers?
Here is what I have tried:
function Ctrl1($scope) {
$scope.$broadcast('Update');
}
Ctrl1.$inject = ['$scope'];
function Ctrl2($scope) {
$scope.updated = false;
$scope.$on('Update', function () {
$scope.updated = true;
});
}
Ctrl2.$inject = ['$scope'];
To see it running: view the Plnkr.
Instead of using $broadcast() a shared service and $watch() might be a better alternative.
var myApp = angular.module('myApp', []);
myApp.factory("MyService", function () {
return {
updated: false
};
});
function Ctrl1($scope, MyService, $timeout) {
$timeout(function () { //Some work occurs and sets updated to true
MyService.updated = true;
}, 1000)
}
Ctrl1.$inject = ['$scope', "MyService", "$timeout"];
function Ctrl2($scope, MyService) {
$scope.$watch(function () {
return MyService.updated;
}, function (oldValue, newValue) {
$scope.updated = MyService.updated;
});
}
Ctrl2.$inject = ['$scope', "MyService"];
Updated Plnkr
It depends on the scopes hierarchy and therefore on where you bootstrap your Ctrl1 and Ctrl2 in your dom.
Say Ctrl1 is the parent of Ctrl2. $broadcast will transmit the event to child scopes: Ctrl2 in this case will notice it (use $on).
If you need to transmit an event from Ctrl2 to Ctrl1, use $emit that transmit the event to parent scopes.

What's the recommended way to extend AngularJS controllers?

I have three controllers that are quite similar. I want to have a controller which these three extend and share its functions.
Perhaps you don't extend a controller but it is possible to extend a controller or make a single controller a mixin of multiple controllers.
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
// Initialize the super class and extend it.
angular.extend(this, $controller('CtrlImpl', {$scope: $scope}));
… Additional extensions to create a mixin.
}]);
When the parent controller is created the logic contained within it is also executed.
See $controller() for for more information about but only the $scope value needs to be passed. All other values will be injected normally.
#mwarren, your concern is taken care of auto-magically by Angular dependency injection. All you need is to inject $scope, although you could override the other injected values if desired.
Take the following example:
(function(angular) {
var module = angular.module('stackoverflow.example',[]);
module.controller('simpleController', function($scope, $document) {
this.getOrigin = function() {
return $document[0].location.origin;
};
});
module.controller('complexController', function($scope, $controller) {
angular.extend(this, $controller('simpleController', {$scope: $scope}));
});
})(angular);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.js"></script>
<div ng-app="stackoverflow.example">
<div ng-controller="complexController as C">
<span><b>Origin from Controller:</b> {{C.getOrigin()}}</span>
</div>
</div>
Although $document is not passed into 'simpleController' when it is created by 'complexController' $document is injected for us.
For inheritance you can use standard JavaScript inheritance patterns.
Here is a demo which uses $injector
function Parent($scope) {
$scope.name = 'Human';
$scope.clickParent = function() {
$scope.name = 'Clicked from base controller';
}
}
function Child($scope, $injector) {
$injector.invoke(Parent, this, {$scope: $scope});
$scope.name = 'Human Child';
$scope.clickChild = function(){
$scope.clickParent();
}
}
Child.prototype = Object.create(Parent.prototype);
In case you use the controllerAs syntax (which I highly recommend), it is even easier to use the classical inheritance pattern:
function BaseCtrl() {
this.name = 'foobar';
}
BaseCtrl.prototype.parentMethod = function () {
//body
};
function ChildCtrl() {
BaseCtrl.call(this);
this.name = 'baz';
}
ChildCtrl.prototype = Object.create(BaseCtrl.prototype);
ChildCtrl.prototype.childMethod = function () {
this.parentMethod();
//body
};
app.controller('BaseCtrl', BaseCtrl);
app.controller('ChildCtrl', ChildCtrl);
Another way could be to create just "abstract" constructor function which will be your base controller:
function BaseController() {
this.click = function () {
//some actions here
};
}
module.controller('ChildCtrl', ['$scope', function ($scope) {
BaseController.call($scope);
$scope.anotherClick = function () {
//other actions
};
}]);
Blog post on this topic
Well, I'm not exactly sure what you want to achieve, but usually Services are the way to go.
You can also use the Scope inheritance characteristics of Angular to share code between controllers:
<body ng-controller="ParentCtrl">
<div ng-controller="FirstChildCtrl"></div>
<div ng-controller="SecondChildCtrl"></div>
</body>
function ParentCtrl($scope) {
$scope.fx = function() {
alert("Hello World");
});
}
function FirstChildCtrl($scope) {
// $scope.fx() is available here
}
function SecondChildCtrl($scope) {
// $scope.fx() is available here
}
You don't extend controllers. If they perform the same basic functions then those functions need to be moved to a service. That service can be injected into your controllers.
Yet another good solution taken from this article:
// base controller containing common functions for add/edit controllers
module.controller('Diary.BaseAddEditController', function ($scope, SomeService) {
$scope.diaryEntry = {};
$scope.saveDiaryEntry = function () {
SomeService.SaveDiaryEntry($scope.diaryEntry);
};
// add any other shared functionality here.
}])
module.controller('Diary.AddDiaryController', function ($scope, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
}])
module.controller('Diary.EditDiaryController', function ($scope, $routeParams, DiaryService, $controller) {
// instantiate base controller
$controller('Diary.BaseAddEditController', { $scope: $scope });
DiaryService.GetDiaryEntry($routeParams.id).success(function (data) {
$scope.diaryEntry = data;
});
}]);
You can create a service and inherit its behaviour in any controller just by injecting it.
app.service("reusableCode", function() {
var reusableCode = {};
reusableCode.commonMethod = function() {
alert('Hello, World!');
};
return reusableCode;
});
Then in your controller that you want to extend from the above reusableCode service:
app.controller('MainCtrl', function($scope, reusableCode) {
angular.extend($scope, reusableCode);
// now you can access all the properties of reusableCode in this $scope
$scope.commonMethod()
});
DEMO PLUNKER: http://plnkr.co/edit/EQtj6I0X08xprE8D0n5b?p=preview
You can try something like this (have not tested):
function baseController(callback){
return function($scope){
$scope.baseMethod = function(){
console.log('base method');
}
callback.apply(this, arguments);
}
}
app.controller('childController', baseController(function(){
}));
You can extend with a services, factories or providers. they are the same but with different degree of flexibility.
here an example using factory : http://jsfiddle.net/aaaflyvw/6KVtj/2/
angular.module('myApp',[])
.factory('myFactory', function() {
var myFactory = {
save: function () {
// saving ...
},
store: function () {
// storing ...
}
};
return myFactory;
})
.controller('myController', function($scope, myFactory) {
$scope.myFactory = myFactory;
myFactory.save(); // here you can use the save function
});
And here you can use the store function also:
<div ng-controller="myController">
<input ng-blur="myFactory.store()" />
</div>
You can directly use $controller('ParentController', {$scope:$scope})
Example
module.controller('Parent', ['$scope', function ($scope) {
//code
}])
module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
//extend parent controller
$controller('CtrlImpl', {$scope: $scope});
}]);
You can use Angular "as" syntax combined with plain JavaScript inheritance
See more details here
http://blogs.microsoft.co.il/oric/2015/01/01/base-controller-angularjs/
I wrote a function to do this:
function extendController(baseController, extension) {
return [
'$scope', '$injector',
function($scope, $injector) {
$injector.invoke(baseController, this, { $scope: $scope });
$injector.invoke(extension, this, { $scope: $scope });
}
]
}
You can use it like this:
function() {
var BaseController = [
'$scope', '$http', // etc.
function($scope, $http, // etc.
$scope.myFunction = function() {
//
}
// etc.
}
];
app.controller('myController',
extendController(BaseController,
['$scope', '$filter', // etc.
function($scope, $filter /* etc. */)
$scope.myOtherFunction = function() {
//
}
// etc.
}]
)
);
}();
Pros:
You don't have to register the base controller.
None of the controllers need to know about the $controller or $injector services.
It works well with angular's array injection syntax - which is essential if your javascript is going to be minified.
You can easily add extra injectable services to the base controller, without also having to remember to add them to, and pass them through from, all of your child controllers.
Cons:
The base controller has to be defined as a variable, which risks polluting the global scope. I've avoided this in my usage example by wrapping everything in an anonymous self-executing function, but this does mean that all of the child controllers have to be declared in the same file.
This pattern works well for controllers which are instantiated directly from your html, but isn't so good for controllers that you create from your code via the $controller() service, because it's dependence on the injector prevents you from directly injecting extra, non-service parameters from your calling code.
I consider extending controllers as bad-practice. Rather put your shared logic into a service. Extended objects in javascript tend to get rather complex. If you want to use inheritance, I would recommend typescript. Still, thin controllers are better way to go in my point of view.

Categories

Resources