How to modify controller property in parent scope from a child scope? - javascript

I have a parent controller that manages the partial in ng-view.
It has 5 tabs, each tab has a form.
Each form has it's own controller.
I am maintaing a variable in the parent scope.
I want to modify it in one of the child controller's scope so that other controller's also view the change.
How is it possible ? Will a statement like
$scope.sharedProperty = 5
make the one in parent as 5, or create a new one with that value in child scope?

Depends upon where you do it and type. If you are using string, int, bool etc and make changes in the child controller, no other controller including the parent would see them, as this would define an new property on the child controller.
If you create a object, such as $scope.sharedObject on the parent controller, then you can manipulate it anywhere in the child such as
$scope.sharedObject.prop1="newvalue";
and all others would see the change and watch over it using $scope.$watch.
Better way to share data between controllers is to use a service.
Also read on prototypal inheritance of $scope here https://github.com/angular/angular.js/wiki/Understanding-Scopes

I would recommend to use as service to share properties, this way you avoid creating dependencies, just think if you need to reuse your view but not as a direct child but as a nested child, using a service angular would manage that for you without worries.
Check this answer for instance.

Agree with #Chandermani about services. But you can also modify parent scope like this:
$scope.$parent.sharedProperty = someValue;

Related

Set context scope in Angular

I have my variables bound to this in my controller, and in my route designation I use controllerAs: 'game'. This allows me to include them in my HTML with {{game.var}}. Sometimes, I bind objects that I want to display, but this forces me to write repeatedly {{game.object.a}}, {{game.object.b}}, {{game.object.c}}.
In a previous project using Meteor, I could set the data context with the with keyword.
{{#with object}}
{{a}}
{{b}}
{{/with}}
but I don't see a similar feature to this in Angular. The closest I've been able to make work is adding the attribute ng-repeat="object in [game.object]". This works, but it isn't very semantic. This also causes me to get a quick flash of a second element when game.object changes, as the new one loads before the first one is erased.
Is there a better solution to this problem?
Angular intentionally uses this context scope to avoid confusion between parent and child scopes. If you're not using child scopes, you can skip the controller as syntax entirely and just bind everything to $scope in your model, which turns game.a and game.b to just a and b in your view.
If you are using child scopes, you can still skip controllerAs, but then it becomes confusing what controller a given model in the view belongs to. There's no with or using syntax, so you need to declare the bound scope game.a, childGame.a everywhere you refer to these models, which might be overly verbose but is at least clear.
See this post, as well.
Regarding the flash issue, I would avoid using ng-repeat for semantic purposes. It's primary use case is to display an array of similarly structured data.

Is ng-init truely a bad way set variable in view without controller

I am using ui-select to create a complex page with multuple views. For those that don't know each view is loaded via ajax when a user selects a tab (or in my case a dropdown). Views traditionally have their own controller and html templet. Views inherrit the scope of the parent page they are on, but have their own child scope.
In my case some of our views have no controller at all. They are so simple that we only have html pages for them. The problem is that I would like them to be able to toggle a boolean on a configuration object on the parent page's scope, to turn off on on some control fields on the parent page. Everything already exists, multiple pages use these views, I simply want to expand them to toggle something on the parent.
I could do this in three ways. I could in my ui-router use the resolve method to explicitly toggle the field I want when the view is loaded, but then I have to do this in each ui-router for each page explicitly; no cool code-reuse.
I could have my ui-router load a controller, where currently I have no controller, and the controller could do this. However, this means manually adding a controller that is mostly unneeded everywhere I use the view, and again doesn't feel like code reuse.
Or I could use ng-init to have my view's explicitly set the value I want at load time. To me this feels cleanest and easiest, since I don't already have a controller.
However, ng-init is frowned on, and should only be used for aliasing supposedly. Is there a cleaner approach then using the ng-init? is it really bad to have a view without a controller (to be more exact they have the parent controller still, but that isn't reloaded when a new view is opened).
The fact that you don't specify controller for the route doesn't change anything. The view has its own scope, so it can be manipulated with either route controller or with directives that don't have their own scope (e.g. ngInit).
The objective of well-known remark on ngInit
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
is to keep you from 'html programming'. And it doesn't have too much sense because the separation of concerns is not among Angular's virtues. Angular's habit of evaluating the code from html attributes and the way how it is used by core directives prompt you to defy it even further.
Just dont init that variables at all. ng-show="smth", ng-if="smth" works ok if 'smth' is not defined and later u change it using ng-click="smth = !smth".

AngularJS - Communicating with multiple instances of a directive from controllers.

I am trying to find the best way to pass data to a directive from any controller.
I have a directive called sideMenu. There will be 2 of these on the screen at any one time. Each can have its own ID.
I need to pass 2 pieces of information into the directive from any of my controllers, an ID and a string.
Typically this would be done with a service/factory and I would simply DI my service into any of the controllers that wish to communicate with the directive, though because they (services) are singleton it doesn't really work in my case - if i, from a controller, need to communicate with both sideMenu's then they both get the most recent data added to the service.
How else can I, from any given controller, pass data to 2 separate instances of the same directive?
The directive's would be outside of the scope of other controllers - the directives would be in the top most parent scope (I have some nested controllers).
Would I be better to set a couple of properties on the $rootScope for each directive and manipulate them as-and-when?

In AngularJS, what's the difference between $scope and the native context?

I'm just starting to look at Angular, but having a hard time wrapping my head around the need for $scope. Javascript already has a concept of scope via the context (i.e. this) and allows programmers to inject that context on a function using call or apply.
Are there any differences between Angular's, $scope, and the keyword this?
If there is a difference, then what is the value of this within a controller or directive?
Thanks in advance :)
Yes, they are not the same at all. The constructor is just an instantiated new ed constructor (the function you wrote) created by the injector.
$scope is more conceptually related to the DOM. In that elements with ng-controller get that $scope and child elements do as well. If a child element with its own scope (controller/directive) had the same properties as the parent scope You wouldn't be able to access them. It also has all of the internal information angular uses in its digest loop (dirty checking/ data binding) like watches,events,etc. I'd have a read through this
As for the myCtrl as syntax, this is nice but all it really does is put the controller instance onto the scope. With the name that you set.
eg myCtrl as foo is basically $scope.foo = myCtrlInstance;. Which you are capable of doing in your controller as well.

When is it appropriate to use a directive scope without its own controller?

My understanding is that the directives should be concerned mostly with DOM interaction and templating. Setting up the application logic related to the $scope is the responsibility of controllers instead.
Yet Angular allows you to create a scope for the directive itself, such as with { scope: true }. If you do this, when are you supposed to initialize like you would in your controller constructor -- in the post-link function? That seems like an inappropriate use of the directive, since it's not concerned with the DOM.
When it it appropriate to use an Angular directive scope instead of creating a controller that must be used with that directive instead?
Yet Angular allows you to create a scope for the directive itself,
such as with { scope: true }. If you do this, when are you supposed to
initialize like you would in your controller constructor -- in the
post-link function? That seems like an inappropriate use of the
directive, since it's not concerned with the DOM.
A directive can have its own controller, defined by the controller option. That controller has the same function as an application controller: to provide behavior for the directive. That said, I think the correct place to initialize the scope is the directive's controller, not its link function.
I think of a directive's controller as the place where you manipulate the scope and of the directive's link function as the place you manipulate the DOM. This SO question has some good insights on that matter.
When is it appropriate to use an Angular directive scope instead of
creating a controller that must be used with that directive instead?
Off the top of my head I can think of two scenarios:
You want your directive to access its parent scope, but don't want it to modify the parent scope's data. In order to do that you need to set the directive to have its own scope, i.e. scope: true.
You want your directive to be reusable. In such a case, the directive shouldn't rely on any parent scope, and should have its own isolate scope, i.e, scope: {}.
I've implemented a directive recently and used the controller function for driving its behavior and
the link function for manipulating the DOM. Perhaps you'd be interested in checking it out. Link here.

Categories