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?
Related
couple questions while i was going through the tutorial that i cannot find the answer to.
https://docs.angularjs.org/tutorial/step_02
1)in View and Template, how does {{phone}} bind to the controller? and what are the ng-controller and ng-app?
2)whats the $scope in Model and Controller?
3)further down in the Testing section, what is the describe function, it function, and what does {$scope: scope} mean in Testing non-global controllers?
4)what does the $ mean in $scope, $injector, etc
You've clearly didn't put enough effort in researching but here's my answer:
{{phone}} binds to the controller via the $scope. $scope is a concept by angular connecting the controller and the view via binding. everything on the $scope is visible on the template. ng-controller is a directive that when specified - lets the element and its children share a common controller. ng-app defines the first module angular loads - the "app".
$scope is the "glue" between the view and the controller allowing all sorts of binding and is the "magic" behind {{phone}}.
describe describes the purpose of the testing unit. it describes what the particular test should do.
I have been reading wrox angular book. Inside the book the author describes that a method of sharing data between controllers is to
Have a property on the root scope
Update that property on the root scope
Broadcast the fact that the property was updated
All children scopes that need to know , will listen for the broadcast.
as opposed to expose an object on a Service and letting angular's two way databinding do all the heavy lifting. Why would anyone go with the 'root scope publish/subscribe' methodology, instead of exposing an object on the service?
That's interesting question.
First we should consider differences on various levels:
Scope
in case of $rootScope we define variable in global scope
in case of shared services we can inject this service to controllers that really use this value
Extensibility
$rootScope - we have limited options to add additional logic to work on this value (we can define another global function)
shared services - we are free to define any kind of logic
Encapsulation
$rootScope - all object defined in $rootScope would be visible in all modules
shared services - we can decide what is visible and what is not
Modularity
$rootScope - global variables is not places in module spaces
shared services - service is a separate module for application
Maintaining
$rootScope - it's very hard to find which components use our $rootScope variable.
shared services - we can see which services we use and we can find in which component we use this service
Binding
$rootScope - it is easy to setup two-way binding in several controllers on one variable in $rootScope
shared services - could be tricky to enable two-way binding
In my opinion this is only useful for make really global variables.
Say you have two controllers A and B, and a service S, storing the common data.
When A changes data in S, B cannot directly change its scope value by understanding that data in S has changed. Someone has to say to it that data in S has changed and update its scope according to this change. This may be done two ways.
One is rootScope broadcast: service S broadcast changes and B listens this broadcast.
The other $scope.$watch: In controller B, scope must watch the changes in service data.
It depends which kind of data you are managing, if you are for example relying on a DB where you perform CRUD actions, you'd like a service to just interact with the DB.
That's called a stateless service, some people vouch for it and some are against and prefer to have state also on the service, exposing the object as you mentioned.
I'll leave you a couple resources with more information on the topic so you can decide which solution suits you best
http://www.johnpapa.net/sharing-data-in-an-angular-controller-or-an-angular-service/
http://www.webdeveasy.com/angularjs-data-model/
Are there strong reasons one should not pass $scope to a service?
I realize services are to be reusable singletons and so passing a (potentially) large object to the service might have maintenance issues, but let's assume solid documentation that would declare "the following members of $scope are required." I just think it looks cleaner than passing in 4-6 parameters.
Any other concerns for this practice would be greatly appreciated. I am being evaluated on this piece of code! :)
Incidentally, I JUST realized how active the angularJS community is on here and I am very grateful!!
Read this article
5 Guidelines For Avoiding Scope Soup in Angular
In point 5, he explains the reason for not passing $scope to Services.
I will quote some of his writing here
The problem with relying on values to be set from a parent controller, or relying on a child controller to set data back up on the parent scope, is that you end up with an implicit coupling that isn't easy to see at first.
Worse, it means the controller implementation is completely dependent on the ordering of the bindings in the view! I can't use or test those controllers independently of each other, because they are coupled together by $scope.
$scope should be used as a glue between View andController. If you want to send some value from $scope to a service, just extract those values out and pass them to the service.
If you see that you are having to pass too many values, consider grouping the values in objects and then passing them.
Changing few things in $scope, might affect your app in unwanted ways.
It is an anti-pattern to use $scope outside controllers.
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;
I'm trying to wrap a 3rd party (non-Angular) library in a set of Angular directives for use in my application. So far I've got a base control that I wrapped in a directive (basically on link it just replaces a div in the template with the 3rd party control). I wanted to setup this directive to be re-used across my app as I'll need the control multiple times. This seemed to call for an Isolate scope and to setup bindings on my views to avoid tight coupling. This works for the base functionality, but in some cases I need to extend the functionality of that control.
My thought was to create a second directive that leveraged different parts of the 3rd party library to add functionality to the base control. This directive would need to communicate with the 3rd party control in the first directive, as well as bind to values on the parent view. I setup both directives as restrict: 'A' to make them attributes, then I stack them on a single div in my view -
<div directive-base directive-add-on />
The problem here is communicating between all the different pieces. If the base directive is an isolate scope, the add-on can't be isolate and thus can't communicate with the parent view. If I make them both child scope I can see everything on the parent scope, but then I'm more tightly coupling my directives to my view's controller.
Is there a different approach to doing this that avoids the tight coupling?
Can you treat the add-ons as attribute arguments to the directive-base?
Normally, I'd have a directive on an element like:
<directive-base add-on="true_or_scope_variable"></directive-base>
In your directive link function or associated controller, you can adjust the content based on the attribute values.
Does this work?