So if in a lot of my controllers I have this:
$scope.error = false;
$scope.errorData = {};
$scope.working = false;
$scope.workingMessage = "Doing something, please wait..."; // best UI message ever
Is there a way of having these permanently defined on every $scope given to my controllers?
So I do need inheritence, so where can apply these scope variables to the $rootScope so that it will be picked up in all my controllers?
Update
So after much reading of the documentation, it appears that use ngApp auto bootstraps the angular app which is when the $injector service runs. I need to have the variables put on before this service runs, so I'm guessing that I need to manually bootstrap the application.
More Work
.run()
This runs after all the modules have been initialised. So here I can inject the $rootScope and put my variables on that. Then they can be used on my all my $scopes, obviously if you data bind to it then you can simply use the property names because the binder will first look at the $scope then all subsequent parent scopes until it finds the property.
.run(['$rootScope', rootScopeConfigure]);
function rootScopeConfigure($rootScope) {
$rootScope.myCustomProperty = "Hey There";
}
As per a comment on my question, this can get dangerous if you are adding properties randomly. But as I have only a few properties, it doesn't really matter or add that much overhead. (I hope).
However, all this poses one problem, if I want to modify this custom property in the controller then I have to inject $rootScope. I don't particularly want to do this, I want to be able to access these on the $scope
In response to my above paragraph, I should be able to do $scope.$root.myCustomProperty because I'm guessing that the $rootScope is the root of all $scopes.
Dirty Answer
$rootScope.$oldNew = $rootScope.$new;
$rootScope.$new = function () {
var childScope = $rootScope.$oldNew();
childScope.myCustomerProp = "Hey There";
return childScope;
}
Do this in the run() function. Basically overriding the factory to return a new child scope that has my property on it :).
Yes, scopes can be inherited from parents. You can create a parent controller for your controllers.
A scope can inherit from a parent scope, as in this example:
var parent = $rootScope;
var child = parent.$new();
parent.salutation = "Hello";
child.name = "World";
expect(child.salutation).toEqual('Hello');
child.salutation = "Welcome";
expect(child.salutation).toEqual('Welcome');
expect(parent.salutation).toEqual('Hello');
https://docs.angularjs.org/api/ng/type/$rootScope.Scope
I recommend not using scope but instead using $cacheFactory or a service/factory of your own to persist this type of state.
So I have the answer now.
.run()
This runs after all the modules have been initialised. So here I can inject the $rootScope override is $new function that I believe is just a simple scope factory.
Then any properties or methods put on that new scope can be used on my all my $scopes.
.run(['$rootScope', runtimeConfigure]);
function runtimeConfigure() {
$rootScope.$oldNew = $rootScope.$new;
$rootScope.$new = function(isolate, parent) {
var child = $rootScope.$oldNew(isolate, parent);
child.title = "Hey There";
return child;
}
}
I believe there to be no issues with doing this.
Firstly, I'm merely ghosting the original scope factory $new
Secondly, I'm just adding properties to the new scope.
Related
$scope.some_random_variable = "random_value";
$scope.some_random_function = function(random_param){
console.log("randomness");
}
I want to know the difference in the context of digest cycle.
As far as I can understand scope_function changes the visibility of Angular Function.
basically, in your html, or whatever that interacts with your $scope, a $scope.something that is declared as a function will be launched when it is called, just like how a javascript function works, same as a variable, only difference between a $scope and a var would be that $scope is a global call.
$I have a custom javascript object, that can fire events.
I would like to access the angular $scope inside the event-handler, but I have read somewhere that using angular.element(...).scope() is not good, because it's only meant for testing.
My other idea was to register the handle on my object inside the controller, but this is not working (looks like $scope.somevalue gets set, but I don't think $scope is the same object).
I have found many answers here on Stack Overflow for similar questions, but they all seem to be using directives. All I want is to get a value from the object when it's updated, and display it.
Here are the two ways I have tried.
var myObj = GetMyObjInstance();
// Working, but apparently it's not good practise to call .scope() on an element.
myObj.onUpdated = function(){
console.log("myObj updated");
var v = myObj.getValue();
var controllerDiv = document.getElementById("controller");
var $scope = angular.element(controllerDiv).scope();
$scope.apply(function(){
$scope.someValue = v;
});
}
// Tried to do this, thinking i would get closure on the scope.
angular.module('myApp', []).controller('controller', function($scope){
myObj.onUpdated = function(){
console.log("myObj updated"); // Gets logged to console...
var v = myObj.getValue();
$scope.somevalue = v; // ... but somevalue does not get displayed.
$scope.apply(); // Error, says it's not a function, so maybe this is not the right object?.
}
});
Use AngularJS directives to handle events and update scope.
app.directive("xdEvent", function() {
return linkFn(scope, elem, attrs) {
elem.on("event", function(e) {
scope.$eval(attrs.xdEvent, {$event: e});
scope.$apply();
});
};
};
USAGE
<div xd-event="fn($event)"></div>
I think using a Service instead of a controller is a better practice. You can call a service from outside javascript with the injector like explained in this thread :
Call angularjs service from simple js code
If it is still important for you to access this variables from controller, you can use $watch to tell your controller to update itself when the service variables change.
Hope this help.
A+
I have the following piece of code in angular
$scope.prepare = function(){
$scope.elems = [1,2,3];
};
$scope.action = function(){
var elem = $scope.elems[0]; //undefined
}
then, in my view, I use the directive ng-init="prepare()" and attach to a button the action function on click event
<button ng-click="action()">action</button>
Inthe action function the scope hasn't the elems array defined?
Can anybody tell me why this happen?
Thanks!
Since you are not showing the controller or the scope of the HTML where you are calling init() and action(), I can't even guess why you are having problems since the code you have posted works. This is a pluker proving that much: http://plnkr.co/edit/qMzPtJtp9t9CoNKkmWIc?p=preview
<div ng-init="prepare()"></div>
<input type="button" value="Call function" data-ng-click="action()" />
<p>Init Defined: {{elems}}</p>
<p>Function call: {{redefined}}</p>
$scope.prepare = function(){
$scope.elems = [1,2,3];
};
$scope.action = function(){
$scope.redefined = $scope.elems[0]; //undefined
}
With that said, you are not using ng-init() correctly. From the angluar documentation:
"This directive can be abused to add unnecessary amounts of logic into your templates. There are only a few appropriate uses of ngInit, such as for aliasing special properties of ngRepeat ... and for injecting data via server side scripting. Besides these few cases, you should use controllers rather than ngInit to initialize values on a scope."
Link to ng-init documentation: https://docs.angularjs.org/api/ng/directive/ngInit
You will be much better off initializing your array in the controller.
What scope is a function defined inside an angular js controller, part of?
.controller('MyCtrl', ['$scope', '$location', function($scope, $location) {
function log() {
console.log('Vanakkam Ulagam');
}
var functionToCall = 'log';
????????[functionToCall]();
}])
I tried MyCtrl, this and $window. I can access the function by namespacing it like so functions.print = function() and then using functions[functionToCall]().
I am more interested in accessing the function without namespacing it. Is it possible? If not, why?
i think this is solution for this question
var f;
var a = angular.module('MyApp',[]);
a.controller('MyCtrl', ['$scope', function ($scope) {
$scope.log=function(){
console.log('test');
}
f=$scope.log;
});
and this function useable to element html for example
<button ng-click='log()'></button>
or
<button onclick='f()'></button>
If you're just trying to access global functions in your controller code, window (or $window if it's properly injected) should work fine:
$scope.alert = function(text) { window.alert(text) }
To be extra sure this works in other environments you could manually bind it in a self-invoking anonymous function:
(function(global){ //make the global scope assigned to the variable global
app.controller('MyCtrl',['$scope',function($scope){
$scope.alert = global.alert;
}]);
)(this); //this is the global object when this is evaluated
If you want to do anything inside an expression on a DOM element (such as ng-click), it's important to realise that angular expressions are evaluated by Angular's own expression evaluator (namely through $scope.$eval). So if something is not attached to a scope, it cannot be used in an angular expression.
However, if you were to do something like attach the global object to the scope, then everything is fair game. This really isn't recommended (I think there's no real reason to do this, and its better to manually define functions you need), but :
$scope.global = window
Inside your controller definition should work. You can then do things like ng-click="global.alert('Yo SO!')" in your DOM without issues.
For better testability you could use $window (you said you tried it and it didn't work... are you sure you injected it properly? Look at the example in the documentation carefully). But like I said, if you're attaching the global object to the scope you're opening Pandora's Box.
Cannot access to $scope and Food inside destroy function.
foodProject.controller('FoodsCtrl', function($scope, Food) {
$scope.foods = Food.index();
$scope.destroy = function(food){
debugger;
console.log(Food, $scope);
food.$destroy();
};
});
The local scope variables are only
food: Resource
this: $get.e.$new.a
I can't find $scope and Food
http://jsfiddle.net/fW2EA/1/
http://jsfiddle.net/wizztjh/fW2EA/3/
Include this line in your destroy function (it is missing from your fiddle):
console.log(Food, $scope);
Then in your debugger, check the Closure section of Scope Variables (I was using Chrome), when stopped on your break point. Food and $scope are in there (as one would expect!).
this in the context of the destroy function is a new scope within the ng-repeat so is not the same as $scope, although both are scopes.
Within your function, this is the scope, e.g. this.foods.
I believe if you want Food to be accessible add it to the scope, i.e., $scope.Food = Food;.
I'm still a noob and am not sure if adding Food to $scope is the right thing to do.