I am wondering if it is possible to open an ons-page as the main page in a ons-sliding-menu and passing it some parameters.
myMenu.setMainPage('somePage.html', [parameter1:'whatever'])
Then, once inside the page, recover them.
I know this can be done in the ons-navigator component. I didn't find any information about this issue.
In case this mechanism would not be available for sliding menu, can anyone recommend me a suitable one?
I am thinking in binding to the $rootScope the parameters I need:
$rootScope.parameter1 = 'whatever'
is this correct? Is there a better option?
Thanks for your help.
You don't need to use the root scope as long as the variable you're setting belongs to a scope that is a parent to that of the new page.
So in your controller you can do something like
$scope.params = {};
And in the ngClick directive:
params.parameter1 = something; myMenu.setMainPage('somePage.html');
I made a simple example on Codepen: http://codepen.io/argelius/pen/GgQVRa
However, a cleaner way would probably be to create a simple service to save the parameter. Then you inject the service in both controllers. If you do it this way you don't have to pollute the scope.
Related
I would like to persuade my co-worker that it is a better approach to use component directives than to use $rootScope everywhere. I need arguments against his ones because he is very stubborn and a very good speaker (which I am not). He thinks that $rootScope prevents spaghetti code. This week I have refactored the project and there are no more spaghetti but I don't want him to rework everything to $rootScope.
Please tell me about problems and issues that can arise when using $rootScope. Thank you.
EDIT
Are there any security issues with $rootScope?
EDIT 2
My friend came with this construct and wants to put it in every component:
function Controller(service, $rootScope, $scope) {
var vm = this;
$scope.a = $rootScope.a;
$scope.b = $rootScope.b;
$scope.c = $rootScope.c;
$rootScope.$watch('mapLoaded', function () {
$scope.a = $rootScope.a;
$scope.b = $rootScope.b;
$scope.c = $rootScope.c;
}, true);
Would the issue of destroying scopes and removing wathces that #charlietfl described in comments appear? I am definitelly not gonna let him code like this but I need the arguments against it. Thanks again.
$rootScope exists, but it can be used for evil
Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject $rootScope and set values on it like any other scope. Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like ng-show just like values on your local $scope.
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
-- AngularJS FAQ
I will response myself to Edit 2 citing this:
Using $watch means whenever you read this code in the future you’ll
have to consider whether it’s being triggered by something else, too.
I'm working my frontend with angular and angular-loading-bar, in the controller I put this code.
$rootScope.$on("cfpLoadingBar:completed",function(){
$(".animated").addClass("fadeIn");
});
or
$scope.$on("cfpLoadingBar:completed",function(){
$(".animated").addClass("fadeIn");
});
When the all XHR requests have returned, I want to add a clase in my section content, but the code inside event don't run.
How is the correct way to achieve it?
Firstly, check that you use appropriate event name. For example, are you sure thet its name is cfpLoadingBar:completed? Maybe its a cfpLoadingBar::completed (its a very common pattern) or something else?
Second, ensure that you have to subscribe to this event using $rootScope. Maybe you have to subscribe for it in some concrete controller witj its own $scope?
And as a big suggestion: DO NOT USE JQUERY AND ANGULAR TOGETHER IN YOU CODE, DO NOT MESS IT UP!!! Angular has a built in possibility to work also as a jquery. All that you need is to call angular.element() which returns you an element as if would use jquery. In your case you can write angular.element(".animated").addClass("fadeIn"); and it will do the same thing, but in angular way
Yeah, I use both cfpLoadingBar::completed and cfpLoadingBar:completed but don't run this event.
In the other hand I only have one controller by one section, it ran but I needed add a main controller and registered this event and propagate up the event with $broadcast in my child controller.
This is code in MainController
$scope.$on('cfpLoadingBar:completed', function(event, data) {
angular.element(".animated").addClass("fadeIn");
});
And This is code in other Child Controller
$rootScope.$broadcast('cfpLoadingBar:completed');
it is the only way to achieve, I don't know why XD
Thanks Andrew this way is better angular.element()
I'm really new on AngularJS and i don't know the best practices so here is my question.
What is the recommended use of parents controllers properties? Should I use different alias trough the entire webapp or there is another way to use vars and methods of a parent controller?
I'm using partials html and seems it can be confusing see userCtrl.doSomething when the partial has no declaration of userCtrl (because its declared on a partial thats includes this one).
Thanks in advance!
You should avoid to use $parent and scope variables that are not declared in your controller.
Why ? Because if you use it, your controller will be directly dependent to where you instantiated it (ng-controller). So you won't respect the MVC pattern. Your controllers should not be dependent on the View.
Your controller should not know what are his parents. Because you can do it doesn't means that you should to it.
To share data between controllers, use Services instead. That's easier and cleaner.
Here's something simple and I think there must be a better way: I often need to navigate to a new view, and at the same time I want to provide some context information to the scope that will be created. I can't figure out how to do both simply -- change the url (resulting in my view/controller being instantiated) and pass some variables I want instantiated in the controller's scope -- for instance, so they can be rendered in the view template
So instead I am doing:
$rootScope.myVar = 'blah';
$location.path = '/newView' ;
and newView.html accesses {{myVar}}
I know this is wrong, what is the simplest solution to avoid using $rootScope like a global dumping ground?
Use case
For use in a form, I created a directive that tracks changes in an array. It allows changes to be reverted and deletions and additions to be stored separately. It allows for an array (one to many mapping in the database) to be updated incrementally (rather than requiring the server to either diff, or rewrite the entire list).
Problem?
My question is about the way I expose the functionality to the controller's scope. I currently use an two-way databound attribute on the directive's scope. This works, and it seems reliable (of course you can easily break it by reassigning the scope's value, but intentionally you can break anything).
Code
You can see this plunk to see this in action. It allows methods on the directive's controller to be called from the view and the view's controller. (I am using the directive controller intentionally because that's what I do in my actual code for the directive to directive communication, but this could also just be placed in the linking function.)
Question
Is this way of doing it bad design? Am I completely throwing AngularJS out of the window now and hacking in my own code. Are there any better ways to expose functions from a directive (keep in mind that there'll be multiple of these in a single form).
It's very easy to pass in my-attribute="someFunction()" to have the directive be a consumer of the view controller. I can't find a better way to do the opposite and have the view controller consume from the directive.
Alternative?
I've been thinking about using a service here, in which the service will provide an object that is instanciated in the view, passed to the directive, and have the directive blurp out it's results to that object. Then in turn have the view controller consume the information from that service's object. Would this be a better approach?
There's nothing wrong with your approach. In fact built-in angular directives such as ng-form use this approach to store the controller in the scope (see the name property of ng-form) http://docs.angularjs.org/api/ng.directive:ngForm
For more re-usability though I would put the api methods on the controller and then put the controller itself in the api:
this.getChanges = function () {};
this.resetChanges = function(){};
$scope.api = this;
In directives, the main purpose of the controller is to serve as an api for other directives (if you didn't need an api for other directives you could just do everything in the link function). Doing it this way ensures the api is available both on the scope as well as to any directive that 'requires' the oneToMany directive.