I'm fairly new to the AngularJS framework, but basically what I am trying to do is inject a CSRF token into my app, but I want to change the url based on a config. Here is what I have so far:
var VERISION_API = 'v1';
var config_data = {
'CFG': {
'EP': 'https://mydomain.com/api/' + VERISION_API + '/web/'
}
};
var configMod = angular.module("cfg",[]);
angular.forEach(config_data,function(key,value) {
configMod.constant(value,key);
});
var myApp = angular.module("app", ["cfg", "ngResource", "ngRoute"]);
(function () {
var $injector = angular.injector(['ng']);
$injector.invoke(['cfg', '$http', '$rootScope', function (cfg, $http, $rootScope) {
$rootScope.$apply(function (CFG) {
$http.get(CFG.EP + "accounts/csrf").then(function (response) {
myApp.constant("CSRF_TOKEN", response.csrf_token);
angular.bootstrap(document, ['app']);
});
});
}]);
})();
I keep getting the following error:
Uncaught Error: [$injector:unpr] Unknown provider: cfgProvider <- cfg
I know it has something to do with the way that I am running the $injector.invoke, but I have tried everything. Hopefully someone could help me out and tell me what I am doing wrong?
Couple of issues, See inline:-
var $injector = angular.injector(['ng', 'cfg']); //<-- Add module name here
/*Injection is case sensitive it mustbe CFG*/
$injector.invoke(['CFG', '$http', '$rootScope', function (cfg, $http, $rootScope) {
$rootScope.$apply(function () { //Do not set an argument here
$http.get(cfg.EP + "accounts/csrf").then(function (response) {
myApp.constant("CSRF_TOKEN", response.csrf_token);
angular.bootstrap(document, ['app']);
});
});
}]);
1) You need to get the injector with the module that has the dependency, example:
var $injector = angular.injector(['ng', 'cfg']);
2) DI service/provider/etc.. names are case sensitive so:
$injector.invoke(['CFG',...
3) Do not pass an argument in the anonymous function of $rootScope.$apply it will create a local variable within that scope. So just:
$rootScope.$apply(function () {
injected dependency is available as variable (argument cfg) from the upper scope, so just access it as:
$http.get(cfg.EP + "accounts/csrf");
Check the network console in the demo:
var configMod = angular.module("cfg", []);
var config_data = {
'CFG': {
'EP': 'https://mydomain.com/api//web/'
}
};
var configMod = angular.module("cfg", []);
angular.forEach(config_data, function(key, value) {
configMod.constant(value, key);
});
var myApp = angular.module("app", ["cfg", "ngResource", "ngRoute"]);
(function() {
var $injector = angular.injector(['ng', 'cfg']); //<-- Add module name here
/*Injection is case sensitive it mustbe CFG*/
$injector.invoke(['CFG', '$http', '$rootScope',
function(cfg, $http, $rootScope) {
$rootScope.$apply(function() { //Do not set an argument here
$http.get(cfg.EP + "accounts/csrf").then(function(response) {
myApp.constant("CSRF_TOKEN", response.csrf_token);
angular.bootstrap(document, ['app']);
});
});
}
]);
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
angular gets service from providerCache by exact the string key case sensitive, so CFG should be used
Related
I want to access variable from another controller any body help
My code
app.controller('MapCtrl',function($scope, $state, $cordovaGeolocation) {
$scope.search_item = function($event,item){
console.log(item);
var lat = item.lat;
var lng = item.lng;
}
});
to
app.controller("homeCtrl", function($scope,$http, $filter ){
});
You can set up a service that 'shares' the variable between the two controllers.
Create a file: services.js in the app/ directory (where app.js is located)
angular.module('app.services', [])
.service('var_transfer_service', function(){
var test_var;
return {
getVar: function () {
return test_var;
},
setVar: function( _test_var ) {
test_var = _test_var;
}
}
})
Now inject this service into the controllers that need variable sharing:
app.controller('MapCtrl',function($scope, $state, $cordovaGeolocation, var_transfer_service) {
$scope.search_item = function($event,item){
console.log(item);
var lat = item.lat;
var lng = item.lng;
var_transfer_service.setVar(lat);
}
});
app.controller("homeCtrl", function($scope,$http, $filter, var_transfer_service ){
var transferred_var = var_transfer_service.getVar();
// transferred_var will now equal 'lat' from the other controller
});
You can further modify the function definitions in services.js and function calls in your controllers to accommodate more variables.
Make sure to also add the services.js module to your app:
angular.module('app', ['ionic', 'app.controllers', 'app.services'])
I have two controllers and in one of them I declared a $scope variable that I would like visible in the second controller.
First controller
app.controller('Ctrl1', function ($scope) {
$scope.variable1 = "One";
});
Second Controller
app.controller('Ctrl2', function ($scope, share) {
console.log("shared variable " + share.getVariable());
});
I researched the best Angular approach and I found that is the use of service. So I added a service for Ctrl1
Service
.service('share', function ($scope) {
return {
getVariable: function () {
return $scope.variable1;
}
};
});
This code return this error:
Unknown provider: $scopeProvider <- $scope <- share
So my question is: is possible share $scope variable between controllers? Is not the best Angular solution or i'm missing something?
Sorry for my trivial question but I'm an Angular beginner.
Thanks in advance
Regards
Yes, it is possible to share the scope variables between controllers through services and factory.But, the $scope variables are local to the controller itself and there is no way for the service to know about that particular variable.I prefer using factory, easy and smooth as butter. If you are using the service of factory in a separate file you need to include the file in index.html
app.controller('Ctrl1', function ($scope,myService,$state) {
$scope.variable1 = "One";
myService.set($scope.variable1);
$state.go('app.thepagewhereyouwanttoshare');//go to the page where you want to share that variable.
});
app.controller('Ctrl2', function ($scope, myService) {
console.log("shared variable " + myService.get());
});
.factory('myService', function() {
function set(data) {
products = data;
}
function get() {
return products;
}
return {
set: set,
get: get
}
})
You cannot inject $scope dependency in service factory function.
Basically shareable service should maintain shareable data in some object.
Service
.service('share', function () {
var self = this;
//private shared variable
var sharedVariables = { };
self.getSharedVariables = getSharedVariables;
self.setVariable = setVariable;
//function declarations
function getSharedVariables() {
return sharedVariables;
}
function setVariable() {
sharedVariables[paramName] = value;
}
});
Controller
app.controller('Ctrl1', function ($scope, share) {
$scope.variable1 = "One";
share.setVariable('variable1', $scope.variable1); //setting value in service variable
});
app.controller('Ctrl2', function ($scope, share) {
console.log("shared variable " + share.getSharedVariables());
});
Your try with service it quite good, but you shouldn't try to use $scope in dependency injection into the service code. Service is meant to be a data provider to you, then if you want to share some data between 2 controllers, you should make place for this data in your service
.service('share', function ($scope) {
this.variable1 = '';
return {
getVariable: function () {
return this.variable1;
}
setVariable(variable)
{
this.variable1 = variable;
}
};
});
app.controller('Ctrl1', function (share) {
$scope.variable1 = share.getVariable();
});
This is the broader description of this solution:
https://stackoverflow.com/a/21920241/4772988
Best way is really using services. Services have only access to $rootScope, they don't have their own $scope.
However, you shouldn't use scopes for this task. Just make a service with some shared variable outside any scopes.
.service('share', function ($scope) {
var variable = 42;
return {
getVariable: function () {
return variable;
}
};
});
app.controller('Ctrl', function ($scope, share) {
console.log("shared variable " + share.getVariable());
// Watch for changes in the service property
$scope.$watch(function() { return share.getVariable(); }, function(oldValue, newValue) {
// whatever
});
});
First, your service should be like this:
app.service('share', function () {
// this is a private variable
var variable1;
return {
// this function get/sets the value of the private variable variable1
variable1: function (newValue) {
if(newValue) variable1 = newValue;
return variable1;
}
};
});
To set the value of the shared variable pass the value to the function we created on the service
app.controller('Ctrl1', function ($scope, share) {
$scope.variable1 = "One";
// share the value of $scope.variable1
share.variable1($scope.variable1);
});
To get the value of the shared variable also use the function in the service without passing a value
app.controller('Ctrl2', function ($scope, share) {
console.log("shared variable " + share.variable1());
});
Update: Using $rootScope is considered bad practice.
What you need is the $rootScope. The $scope is just for one controller. Here is an example:
angular.module('myApp', [])
.run(function($rootScope) {
$rootScope.test = new Date();
})
.controller('myCtrl', function($scope, $rootScope) {
$scope.change = function() {
$scope.test = new Date();
};
$scope.getOrig = function() {
return $rootScope.test;
};
})
.controller('myCtrl2', function($scope, $rootScope) {
$scope.change = function() {
$scope.test = new Date();
};
$scope.changeRs = function() {
$rootScope.test = new Date();
};
$scope.getOrig = function() {
return $rootScope.test;
};
});
I think I am having a similar problem with AngularJS like many others.
I was fixing a previous error message (that I could not call
controller functions from within test describe blocks) and got new
errors.
Error: [ng:areq] Argument 'fooController' is not a function, got undefined
I have read other post but still can't correct it.
so my controller is like..
'use strict';
var app = angular.module('MyApp', ['MyAppControllers']);
var appControllers = angular.module('MyAppControllers', []);
appControllers.controller('fooController', ['$scope', function ($scope) {
function foo(param) {
alert("foo called");
}
}]);
and my controllerspec is..
'use strict';
describe('fooController', function () {
var $scope, $controller;
beforeEach(inject(function ($rootScope, $controller) {
$scope = $rootScope.$new();
ctrl = $controller('fooController', { $scope: $scope });
}));
it("should write foo called", function () {
$scope.foo();
});
});
why does it keep saying fooController is not a function??
Thanks you all.
Old Post edited. Would you please read the bottom post (my new question? :))
change controller
appControllers.controller('fooController', ['$scope', function ($scope) {
//add your function within scope
$scope.foo = function(){
alert("foo called");
}
}]);
well. I was dumb. I didn't put after describe.
So I fixed the problem now with:
'use strict';
describe('fooController', function () {
**beforeEach(module('MyApp'))**;
var $scope, ctrl;
beforeEach(inject(function ($rootScope, $controller) {
$scope = $rootScope.$new();
ctrl = $controller('fooController', { $scope: $scope });
}));
it("should write foo called", function () {
$scope.foo("aa");
});
});
and controller..
'use strict';
var app = angular.module('MyApp', ['MyAppControllers']);
var appControllers = angular.module('MyAppControllers', []);
appControllers.controller('fooController', ['$scope', function ($scope) {
function foo(param) {
alert("foo called");
}
}]);
I would like to ask about my original problem now if I could.
the problem is that function foo cannot be seen from controllerSpec's testing blocks
TypeError: undefined is not a function
I saw a post saying function is private and should turn the function into l
$scope.foo = function(param){alert("foo");};
But 'use strict' prohibits turning function like above.
I was wondering how others is doing about this problem?
Thank you again.
I am trying to obfuscate my angularjs app and it is breaking. I am aware that this is an issue with the framework and they have tried to remedy it via the $inject method.
http://docs.angularjs.org/tutorial/step_05 See the "Note on Minification" section.
To resolve this they recommend doing YourController.$inject = ['$scope', '$http'];
I went ahead and did that to match my application like so:
AventosController.$inject = ['$scope','$http','$q','controllerComm'];
VforumController.$inject = ['$scope','$http','$timeout','controllerComm'];
Well, it still isn't working. The error I receive in the console is:
Error: Unknown provider: cProvider <- c <- controllerComm
Anyway to remedy this?
EDIT
controllerComm
app.factory('controllerComm', ['$rootScope', function($rootScope)
{
var showVforum = {};
showVforum.result = false;
showVforum.prepBroadcast = function(val)
{
this.result = val;
this.broadcastVal();
}
showVforum.broadcastVal = function()
{
$rootScope.$broadcast('toggleVforum')
}
return showVforum;
}]);
EDIT 2 not working after obfuscation
$scope.launchVforum = function()
{
$scope.installationVideo = ($scope.installationVideo) ? false : true;
controllerComm.prepBroadcast($scope.installationVideo);
}
Try injecting at the controller definition.
app.controller('myCtrlr', ['$scope', '$http', '$q', 'controllerComm', function ($scope, $http, $q, controllerComm) {
...
}]); // end myCtrlr
Also is "controllerComm" defined?
Let's take the example from AngularJS tutorial
function PhoneListCtrl($scope, $http) {
$http.get('phones/phones.json').success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
}
//PhoneListCtrl.$inject = ['$scope', '$http'];
Now, lets say I don't want to hard code the url 'phones/phones.json' and would prefer the page which hosts this controller to inject it, what should be the right way of doing the same in Angular JS?
There are a lot of ways to do this... the simplest way would just be to use $window, so you'd inject the $window service, and that's basically just the global $window that's been injected. Then you can register those paths as window.path = 'whatever.json'; and you'll be fine:
window.path = 'some/path.json';
function PhoneListCtrl($scope, $http, $window) {
$http.get($window.path).success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
}
A more advanced way would be to create a module with a service that you inject into your app, in this case each page would have it's own module:
//create your module.
angular.module('configData', [])
.factory('pathService', function () {
return {
path: 'some/path.json'
};
});
//then inject it into your app
var app = angular.module('myApp', ['configData']);
app.controller('PhoneListCtrl', function($scope, $http, pathService) {
$http.get(pathService.path).success(function(data) {
$scope.phones = data;
});
$scope.orderProp = 'age';
});
You can, of course, do anything in between the two. I would suggest taking the path that is the most maintainable while still easy to test.