Well my problem is I have 2 controllers... and I wanna know whether is possible call any function from them in order to do work them together...
For instance:
firstController.js
angular.module('myApp').controller('FirstController', ['$scope', 'FirstService', function($scope, FirstService) {
function verify(){
//Some operations
}
}]);
secondController.js
angular.module('myApp').controller('SecondController', ['$scope', 'SecondService', function($scope, SecondService) {
function edit(iditem){
//Some operations
//I wanna call here verify() function
}
}]);
Is this possible?
Thanks in advance!
You could do it with only one service and call service from both controllers. This is a basic example, you could add a constructor and pass it $scope for example it depends on what you want to accomplish.
'use strict';
/**
* Service
*/
angular.module('myApp.someService', [])
.factory("someService", function () {
return {
verify: function() {},
edit: function(iditem){
self.verify();
}
});
Then your controllers would look like this:
angular.module('myApp').controller('FirstController', ['$scope', 'someService', function($scope, someService) {
service.verify($scope);
}]);
angular.module('myApp').controller('SecondController', ['$scope', 'someService', function($scope, someService) {
service.edit(iditem);
}]);
Using Prototypical Inheritance
If the controllers are nested:
<div ng-controller="FirstController">
<div ng-controller="SecondController">
</div>
</div>
If the FirstController publishes its functions on $scope, the nested controllers can invoke the functions by prototypical inheritance.
Publish function on $scope:
app.controller('FirstController', function($scope) {
$scope.firstVerify = verify;
function verify(){
//Some operations
}
});
Invoke by $scope inheritance:
app.controller('SecondController', function($scope) {
function edit(iditem){
//Some operations
//I wanna call here verify() function
$scope.firstVerify();
}
});
This will only work if the second controller's scope is a child scope of the first controller's scope.
As you can see, there are many answers to the question. Which answer to use depends on the specific use case.
You can do that through $rootScope controller
include $rootScope in FirstContoller, assign a function:
$rootScope.myFirstController_verify = verify;
And call it from second controller with $rootScope included:
$rootScope.myFirstController_verify();
Related
UPDATE PLEASE HELP:
Tried what you suggested, the problem is when i try to pass the value to another "Module". Tried creating a service but the function didn't work, maybe i missed something.
Made Example Using rootScope:
var informes = angular.module('informes', ['angular-drupal', 'ui.bootstrap']);
informes.controller('InformesCtrl', ['drupal', '$rootScope', '$scope', '$http', 'InformesFtry', function(drupal, $rootScope, $scope, $http, InformesFtry) {
$rootScope.nodeID = function(item){
var item = "hi";
console.log(item);
}
}]);
Console hi
It works in first module, but...
In my other Module with different Page...
var nodeInformes = angular.module('node-informes', ['informes']);
nodeInformes.controller('NodeInformesCtrl', ['drupal', '$rootScope', '$scope', '$http', 'InformesFtry', function(drupal, $rootScope, $scope, $http, InformesFtry) {
$scope.nodeID2 = $rootScope.nodeID(item);
console.log($scope.nodeID2);
}]);
Console: item is Undefined
I'm trying to figure out of how can i pass a function to another module, but it seems that it is impossible. I didn't try to use same module, but it works if the controller is child from the first controller.
I really apprecaite any help you can provide me to pass a function with parameter to another module with another controller. I'm trying to learn with this. Thanks!!!
EDIT: If i add the firstcontroller as a dependency it gives me Unknown Provider... Sorry for my mistake.
In Angular JS there are three ways for controllers to communicate with other controllers, and any other method is asking for trouble:
Use a service:
Use a service as an intermediary between controllers:
function MyService() {
this.MyObject = {};
}
function ctrl1(MyService) {
Myservice.MyObject = {
someData: "someValue"
};
}
function ctrl2(MyService) {
$scope.someValue = MyService.MyObject.someData;
}
Use the event system
function ctrl1($rootScope) {
$rootScope.$broadcast("my-event", {someData: "someValue"});
}
function ctrl2($scope) {
$scope.$on("my-event", function(event, params) {
$scope.someData = params.someData;
});
}
Scope inheritence
<div ng-controller="ctrl1">
<div ng-controller="ctrl2">
</div>
</div>
function ctrl1($scope) {
$scope.someData = "someValue";
}
function ctrl2($scope) {
console.log($scope.$parent.someData); //"someValue"
}
Say I have a controller:
app.controller('HomeCtrl', Com.Xyz.ModuleHome.HomeController);
Com.Xyz.ModuleHome.HomeController is a controller function which has parameters like $scope, $window, $timeout, $http, ... these parameters are injected by AngularJS.
But I want to pass some parameters to the controller when it is registered. This is because my controllers are loaded from different domains by RequireJS, now I want to a controller to know where itself is from.
var myVar = jsFileUrl; // jsFileUrl is provided by RequireJS
// I wish the code looks like below
app.controller('HomeCtrl', Com.Xyz.ModuleHome.HomeController, myVar);
// AngularJS will inject a $controllerContext representing controller itself
function Com.Xyz.ModuleHome.HomeController($controllerContext, $scope) {
$scope.controllerJsFileUrl = $controllerContext.Argument;
}
Is it possible? Maybe there is something I didn't know.
I know a service can do it, but I don't want the controller to depend on a special service name. In the future I may move the controllers to somewhereelse.
Since you are looking for the anti-pattern, you could try using function.bindand pass the argument in the bound function. This will let the value of myVar to be passed in as first argument when the constructor is invoked (everytime).
app.controller('HomeCtrl', Com.Xyz.ModuleHome.HomeController.bind(null, myVar));
var app = angular.module('app', []);
var myVar = 1234;
function Ctrl(myVar, $q, $http) {
console.log(arguments);
}
app.controller('ctrl', ['$q', '$http', Ctrl.bind(null, myVar)]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
</div>
The above approach though short is tricky because you can no longer use controller instance as this as it would not the controller instance anymore instead it would be window. Another way is to create a dummy wrapper for the controller and new up the actual constructor.
.controller('ctrl', ['$q', '$http', function($q, $http) {
return new Ctrl(myVar, $q, $http);
}
]);
Assume we have a controller: ProjectsNewCtrl
What is the difference between:
Setting up the controller without an init() function
App.controller('ProjectsNewCtrl', ['$scope', '$location', 'API'
function ($scope, $location, API) {
API.Project.query().$promise
.then(function (projects) {
$scope.projects = projects
})
}])
AND
Setting up the controller with an init() function
App.controller('ProjectsNewCtrl', ['$scope', '$location', 'API'
function ($scope, $location, API) {
$scope.init = function(){
API.Project.query().$promise
.then(function (projects) {
$scope.projects = projects
})
}
$scope.init()
}])
AND finally:
Setting up the controller via:
<div ng-controller="projectsNewCtrl" ng-init="init()">...</div>
App.controller('ProjectsNewCtrl', ['$scope', '$location', 'API'
function ($scope, $location, API) {
$scope.init = function(){
API.Project.query().$promise
.then(function (projects) {
$scope.projects = projects
})
}
}])
There is no real reason why you would want to use ngInit in this way. In your second example, you are calling a function(ngInit) to call a function($scope.init), instead of the first example where you only call one function on initialization. The logic maybe the same, but it adds unnecessary complexity.
As an aside, you should try no to use ngInit as little as possible, coming from the documentation:
The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
Preference. Your last 2 examples are essentially the same, the logic that should be ran on initialization is within the init method - one is called from the view and the other the controller. IMO - it's all about readability, choose what you like.
I asked a similar question earlier when attempting to inject $scope and $http into a controller Cannot call method 'jsonp' of undefined in Angular.js controller. Now I'm attempting to refactor that code slightly by moving the code into a function within the controller. I'm encountering similar issues and can't seem to grasp the mechanics of dependency injection in Angular. Below is my new code. Both $scope and $http are undefined. What I'm attempting to do is make an http request when didSelectLanguage() fires and assign the resulting data to the "image" variable in the $scope from the parent controller. Can someone enlighten me as to how dependency injection is supposed to work in this example?
angular.module('myApp.controllers', []).
controller('ImagesCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.didSelectLanguage=function($scope, $http) {
console.log($scope);
$http.jsonp('http://localhost:3000/image?quantity=1&language='+this.language+'&Flag=&callback=JSON_CALLBACK')
.success(function(data){
$scope.image = data;
});
}
}])
When you create your controller:
angular.module('myApp.controllers', []).
controller('ImagesCtrl', ['$scope', '$http', function ($scope, $http) {
// ...
}]);
The stuff inside the body of the controller function automatically has access to $scope and $http because of closures. Thus, there's no need to specify anything additional for a function on the $scope to have access to these things:
angular.module('myApp.controllers', []).
controller('ImagesCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.didSelectLanguage = function() {
$http.jsonp('http://localhost:3000/image?quantity=1&language=' + this.language + '&Flag=&callback=JSON_CALLBACK');
.success(function(data) {
$scope.$parent.image = data;
});
}
}]);
When didSelectLanguage is run, it sees the references to $http, and reaches out of the function into the outer function to get the value of the reference; the same happens for $scope inside the success callback.
So, in short, there's no need to pass any arguments to your didSelectLanguage function, nor is there in this case any reason to use the $injector.
With the help of Michelle Tilley's comment & article I solved the problem as follows. However, I'm going to keep the question open until someone else answers or until I understand enough to write an accompanying explanation.
controller('ImagesCtrl', ['$scope', '$http', '$injector', function ($scope, $http, $injector) {
$scope.didSelectLanguage=function() {
$http.jsonp('http://localhost:3000/image?quantity=1&language='+this.language+'&Flag=&callback=JSON_CALLBACK')
.success(function(data){
$scope.$parent.image = data;
});
}
}])
There is a lot of reusable functionality that I have defined in my application that EVERY controller uses with the $scope variable. Instead of me having to create a shared service each time, is there a way to extend the $scope variable so that I can have my extended code available everywhere?
Something like:
//I've tested this out and it doesn't work, but this is what I want to do.
angular.module('App',[]).config(['$scopeProvider',function($scope) {
$scope.method1 = function() { ... };
$scope.method2 = function() { ... };
}]);
Then later on:
var HomeCtrl = function($scope) {
$scope.method1();
};
Is this possible? Or do I need to create a shared service and then have the $scope extend from that for the first line of each controller?
Instead of .config try .run, this will do exactly what you want.
angular.module('App', []).run(['$rootScope', function($rootScope) {
$rootScope.foo = function() {
alert("WIN!");
};
}]);
angular.module('App').controller('HomeCtr', ['$scope', function($scope) {
$scope.foo(); #will call the alert
}]);
NOTE I have only used module.controller because I like it, var HomeCtrl = function($scope) { will have the same effect.