I'm having a problem with the scoping of this inside of an angular-ui bootstrap modal. When I run the following code outside of a modal I have no problems with it:
var GlobalVariable = GlobalVariable || {};
(function(){
doSomethingWith(GlobalVariable.field);
})();
When called outside of the $modal GlobalVariable.field is perfectly accessible. As soon as I run this code inside a $modal, GlobalVariable.field is undefined. Now I can fix this problem by directly accessing window.GlobalVariable.field inside the $modal dialog but the problem is that the doSomethingWith method in this case is a 3rd party library which needs access to the global variables. I'm not about to go through all the third party libraries and add "window." on to all of the globally scoped variables.
I know that when I call $modal.open passing in some HTML that it gets mangled through the angular $compile function (which I presume eval()s the HTML as part of the process). My guess is that when $compile processes it, it assigns it a fresh this object meaning we don't inherit all of the globally scoped variables from window.
Is there any way that I can get angular's $compile to force 'inheritance' of the window's global variables all the way down to my modal?
Have a look at this Plunker that I generated from the Angular-UI bootstrap documentation:
http://plnkr.co/edit/jMcvTBDcrkPU7p4gFejT?p=preview
resolve
As you can see, the modal creates a new scope, so anything you want to use inside that scope must be passed in using "resolve" and returned. There's no need to force inheritance when you can just pass whatever you need in.
Related
Why does onclick="window.history.back()" work and angular's ng-click="window.history.back()" doesn't?
You can make this work adding window to your $scope, or even better to $rootScope so every $scope has access to window and thus your initial attemp would work as you've expected.
Example adding it to $rootScope:
<script>
app.run(['$rootScope', function($rootScope) {
$rootScope.window = window
}])
</script>
Then you just call:
<button type="button" ng-click="window.history.back()">Go back</button>
or:
<button type="button" ng-click="window.alert('it works!')">Alert!</button>
or whatever variable or function in global javascript scope you want.
onclick is an javascript event, so it can call function in javascript window object.
Where as
ng-click is an angular directive, which can only call functions which is available in the $scope. window is not available in $scope.
because in the template you use the controller or directive scope. So angular expects the scope object to have a property named window instead of searching for it in the global scope of the script
onclick="window.history.back()" works because it is vanilla JavaScript and onclick is an event on the element.
ng-click="window.history.back()" doesn't work because ng-click is an angular directive and angular is looking for an object called window on the controller's scope.
You can gain access to the window object, in angular the suggested way is to declare a dependency on the $window service and do any operations required on the $window object.
Reasons to use $window service: it helps to do unit testing when using $window service and not the global window object.
EDIT: below info used from Pro AngularJS book - chapter 19
Why and When to Use the Global Object Services
The main reason that AngularJS includes these services is to make testing easier. I get into testing in Chapter 25, but
an important facet of unit testing is the need to isolate a small piece of code and test its behavior without testing the
components it depends on—in essence, creating a focused test. The DOM API exposes functionality through global
objects such as document and window. These objects make it hard to isolate code for unit testing without also testing
the way that the browser implements its global objects. Using services such as $document allows AngularJS code
to be written without directly using the DOM API global objects and allows the use of AngularJS testing services to
configure specific test scenarios.
onclick is an js event, so it can call function in javascript window object.
But
ng-click is an angular directive, which can only call functions which is available in the $scope. window is not available in $scope. In angularjs we can do this by:
ng-click="doTheBack()"
$scope.doTheBack = function() {
window.history.back();
};
I'm making a dynamic web page with angular, the content from the main page should change, but to avoid writing too much code i decided to make it generic, but to know what type of content is being requested i need to send this parameter from a link/button with a ng-click, this would'nt be a problem but when i have to change the controllers i can't read the parameter.
ng-click="name='Name change'"
Here i'm trying to change a $rootScope variable named name, i tried
ng-click="$rootScope.name='Name change'"
even with a service function, but looks like doesn't work (i don't know too much about angularjs so i tried )
ng-click="$service.cambiarTipo='Name change'"
i made a plunker http://plnkr.co/edit/1BN76SbUAHuOSHs02gpL?p=preview
If you check the console log, you will see that the variable it's undefined, obviously if i change $rootScope.name from a controller i can see it from the other controller, but that's not useful since i need that feed from the user not the controller.
How i can change a rootScope variable from html?
Here'a one using a shared service between the two controller without using $rootscope at all. http://plnkr.co/edit/maKNHgVH20GxTJeCEveh
Note that ng-click is calling the service function. I'm assuming the function is for changing the name.
ng-click="service.cambiarTipo('Name change')"
You really shouldn't be using $rootScope all that much, let alone modifying it from the template. With that said, you can assign $rootScope to a $scope variable and access from the template like normal scoped variable. plunker
Controller:
$scope.rs = $rootScope
Template:
rs.name = 'Name Change'
I would like to reiterate that this is not something you should be doing as it goes against the angular way.
I'm building an app with Browserify, so everything is packaged up into commonJS modules and separated out of the global name space, which is generally a great state of affairs.
I've had to open up another page inside of an iframe which opens as a modal in my app. Once the user saves his work inside of that page that page needs to call out to my app to tell it to close the modal.
The only way I know of to call outside of an iframe is to use parent.window. But I'm unclear how to get from the global namespace inside of the modules packaged up with browserify.
I have tried to assign a function to an identifier on the window object within one of my modules, but after the code runs, if I interrogate the window object, my function is not there.
I have tried to follow the example in this post, but I'm not having any luck.
Defining global variable for Browserify
Thanks
All you have to do is assign the object explicitly to the window object and it will be there. For instance, with jQuery, you'd just make sure something like this was present in the code you're bundling with Browserify:
window.$ = window.jQuery = require('jquery');
I'm trying to use a JavaScript variable created globally (inside index.html file head section) inside my angularJS controller. Unfortunately, I also have to use grunt to create a minified version of every file in my project, and so variable assignments get altered.
What should be along the lines of this:
$scope.adminName = adminName (global variable set in head)
ends up becoming something like:
var a = e;
Or some BS like that. I cannot post the example due to restrictions placed on us. But basically, how do you pass a global JavaScript variable into an AngularJS controller while also ensuring that during the minification process (when variable names get altered), it's still valid.
I have an HTML file which imports two files:
graph.js and main.js
The main file contains logic which accesses a phone's accelerometer/records acceleration and it is a purely javascript file. The Graph.js file contains a single JQuery function $(.....)
Is it possible to access a variable in main.js from graph.js?
Yes jQuery is written in JavaScript and it can access any variable declared in that page via import of other JavaScript files. As you are trying to access variable in onload of document, I don't see any problem, because other scripts should already have been loaded before that.
Yes.
if it is in global scope, yes.
It should be, so long as the main.js loads first and if you set it as a global variable.
You make a global variable by creating it outside of a function. If needed, you can create it outside a function, then set it inside a function in the main.js file.
You can freely share variables between different JS files (a jQuery file is just a JS file) in several different ways:
Define the variables in the global scope, then they can be accessed anywhere.
Define variables on the window object. This makes them globally accessible even if your code defining the variables isn't in the global scope.
Define variables as properties on any object that you can get to from your code. So, if you have a global config object called myConfig, you could define properties on it like myConfig.count = 0; and you can then access myConfig.count from anywhere. This is often referred to as namespacing and creates only a single global object which you then add multiple properties to.
Define a globally accessible function that returns your data that you can call from anywhere.
When designing how this works, remember that it's generally better to introduce as few globally accessible symbols as possible because each one is an opportunity for a conflict with some other code in the page.