Multi view bind with same controller? Best Solution? - angularjs

I hope everyone doing great.
I have one controller with couple of views. What I want is when I delete some notification from List A, then the model of List B should be updated.
The best & optimized solution for this problem?
One way is that I make a service and shared the list model with both controller. But is there any other best way?

Either you share the data via a service or factory as you mentioned. Or you can use $rootScope.$broadcast events to communicate between the instances of the controller.
Another way is to have the state in a parent scope, and then pass that state down to both its children via attributes on the component/directive. E.g.
<my-first-directive shared-data="sharedData"></my-directive>
<my-second-directive shared-data="sharedData"></my-directive>
This way you can make the recieving directives/components stateless.

1. you can share rootscope variables for the list view.
Using RootScope Variables and Functions are not professional
2. you can use one controller for both views.
If the codes of two views are not much, you can use one controller for both views.

I guess, the best way is not to create two same views for different components. As for me, better practice is using angular routing, so you can use one state through different routes:
$stateProvider.state("my_state", {
url: "/myView",
templateUrl: "/views/my-view.html",
controller: "MyCtrl"
});
P.S. Don't use $rootScope for this purposes, it's not good practice!)

Try to do this way.
.when('/company/ticket/log/:company_id', {
templateUrl: 'views/company/company_ticket_log.html?v=' + CONFIG.VER,
data: {
authorizedRoles: [USER_TYPES.LOGINUSER]
}
});
When you try to do this, use list data in url and list data can be in shared controller like const.js

Related

Is it good or bad to specify controller in templates only?

I found myself annoyed when I need to specify which controller to use for a template every time I use it for a route or a directive. It get worse when template coupled to a controller with controllerAs syntax, and I have to remember which name it has to be.
$routeProvider.when('/', {
templateUrl: 'stateTemplate.html',
controllerAs: 'ctrl',
controller: 'StateController'
});
ngDialog.open({
template: 'stateTemplate.html',
controller: "StateController",
controllerAs:"ctrl"
});
I’d rather prefer to specify ng-controller StateController as ctrl in the template and totally skip controller and controllerAs in the other places.
The question is: does this approach has some pitfalls I don’t see now? Why it's bad (if it is)? Are the benefits of explicit controller and controllerAs parameters against using ng-controller in the corresponding template? Where canI learn more about it?
I think a lot of people are misunderstanding your question. Am I correct in paraphrasing it as:
What is wrong with only defining a view in your Route Config and then binding that view to a controller using ng-controller="StateController as ctrl"?
So instead of your examples above you would have:
$routeProvider.when('/', {
templateUrl: 'stateTemplate.html',
});
ngDialog.open({
template: 'stateTemplate.html',
});
Then in your stateTemplate.html you would have something like:
<div ng-controller="StateController as ctrl">
<h1>State</h1>
. . .
</div>
Is this what you are asking?
If so, nothing is wrong with this. You will lose the ability to reuse controllers with different views. But honestly that might not be a real concern.
If you use bindToController in directives (you should) you will still want to declare the controller in the Directive Data Object rather than use ng-controller. bindToController causes the property to be bound to the controller before the controller is instantiated.
The other thing you will lose out on is controller dependancy resolve objects.
With uiRouter and ngRouter you can use a resolve object that will then get passed into the controller when the dependancies are resolved. For instance you do not want to display the user details page until the call to get the user details has been returned. Once it is returned it can be passed into the constructor of the controller. This is another thing you will lose out on using with ng-controller. https://github.com/johnpapa/angular-styleguide#resolving-promises-for-a-controller
I am sure there are other benefits to using the declared controllers in the route config. Maybe someone else will point them out.
That said, there is nothing wrong with using it. You should probably be consistent with it so that your code is predictable. If you choose to use ng-controller, it may not not be a big deal to change it in the future. Especially if you have protractor web tests set up so that you know you haven't broken anything.
The quickest answer - bad.
You cannot define business logic inside controller template. What if you need to use now 30 different controllers? are you going to specify 30 different controllers? It's messy, it's unadvised and it's a bad practice all together.
It's like writing BLL inside the input logic layer, or authentications in client side code. You are just making it hard on yourself here.
Defining controllers in templates is defiantly not the answer you are looking for.

Use controller view for email view CakePHP 2

What is a good way to use a controller action's view as an email template? Currently have have two separate views: one in ../View/Emails/html/example.ctp and one in ../View/Example/example.ctp. This is too wet and is giving me headaches.
Q. What is the best way to dry this up and use the same template for both?
Controller has a render method you may call explicitly
http://book.cakephp.org/2.0/en/controllers.html#rendering-a-specific-view
and pass a ../path/to/email/template
or you may extract a common element:
http://book.cakephp.org/2.0/en/views.html#elements

How to communicate between controllers while not using SharedService between them?

I was reading all the answers about communication between controllers and directive, but is seems to me occurred using shared service and inject it to each one of them. When I'm developing a very large scale application, I don't know what my page is going to have in it. I may have 2 controllers need to communicate between them, and I also may have 5 directive and 2 controllers in the same page. I don't know from scratch what is going to be inside my view/page, so I need a better way how to communicate between them. I'm looking for that better way to do it, the right AngularJS way.
http://i60.tinypic.com/2z87q05.png
Above is my view example I'm working on: on the left side I have a directive tree, on the right side I have chart controller and directive grid. I may have more than this, but this is a good example of what I may have. Keep in mind, the view can have X componenets, you don't know from the beginning what will be in it.
Now, lets say each time I select node in tree on the left, I want to be able to tell the other controllers that nodeSelectedChange event happend. I don't want to inject each one of them a service that holds that info, so I thought about something like having a Page Manager Controller, which is the father of the all view. All my controllers/directives inside my page should talk with each other only by the PageManagerController, he is the only thing in page that knows what he has inside of it.
Important here to keep in mind: The tree don't know the page has chart or grid, they don't need to know each other in order to communicate. The page manager knows everything, now I want it to make the magic - Should it has a service? Should each other component has service and service can talk with PageManager service?
Help me to think. Hope I can connect all the dots to create a BETTER way for communication.
I think the sharedService way is good for small app, when you know from start what is going on in your app, but most of the time - You just don't know who and when is going to use your directive, it should be able to talk with everyone.
What I don't like about events:
The events being fired inside the controller, while it should be inside a service.
The listener controller should know the name of the event he is going to listen too. If I change the event name being $emit or $broadcast, I need to go all over the listeners $on("eventName") in all app and change to that unique name.
Directive is like a black box, I don't want to check inside of it each time and find the names of the events he is being broadcasting in order to communicate with it.
I need a way to exposed the events NAMES out of the directive, probably with a service connected to that controller.
There are a couple of good practices:
Use the $scope to communicate between directives and controllers for runtime dependencies (e.g. models you fetch from the server, instantiated classes, etc.). The way to go is to have an isolated scope with attributes mapped to the dependencies:
directive('tree', function(){
return {
scope: {
somevalue : "="
}
}
});
Use it like this:
<tree somevalue="objectFromController">
Use the injected services to communicate with static dependencies (Presentation Models, global sharable state, etc.)
directive('tree', function(treeState){
return {
scope: {
somevalue : "="
},
link: function(scope){
// some logic updating the treeState
treeState.openNodes = ['x', 'y'];
}
}
});
controller('ctrl', function($scope, treeState){
// react to treeState changes
// you can use $scope.$watch for it
// or any other way you like
// see: https://github.com/mr-mig/angular-react-to
});
If you want to have maximum composability, stick to the first pattern:
directive('tree', function(){
return {
scope: {
model : "="
},
link: function(scope){
// some logic updating the treeState, stored as scope.model
scope.model.openNodes = ['x', 'y'];
}
}
});
controller('ctrl', function($scope, treeFactory){
$scope.treeModel = treeFactory.create();
// react to treeState changes
// you can use $scope.$watch for it
// or any other way you like
// see: https://github.com/mr-mig/angular-react-to
});
And compose this stuff using template and binding as a communication bus:
<tree model="treeModel">
Sticking to this pattern you get:
No events
Well-defined directive "interface" (attributes in the isolated scope)
Easy composability
Reactive behavior based on scope change propagation
It really depends on the type of information you want to share from the tree directive to the other sections of the page.
You have a few options in front of you:
Use Scope Events
As someone mentioned above, you could fire an event and listen for events in various controllers and/or services. That said, it can get really ugly, really fast. Tracing events and figuring out what event listeners are active at a given point can give the best engineers a migraine!
Use a Service
Another option would be to use a Service, let's say a PageManagerService. In that case,
Each click of a tree item would set some information on the PageManagerService, saying which page, what objects, and what items it needs to display
Each component that needs to change could
Register a listener to be triggered when the PageManagerService changes
Add a watch on the service and run its code when the PageManagerService changes
The service itself is just going to be shared state, and it would be upto the directives and components on how it wants to consume and respond to changes in the state.
Use UI Router
But the more I think about this, the more it seems like a good use case from something like UI Router. UI Router allows you to define states, and have different parts of the page respond in different ways to state changes. Each section could respond to a state change in its own way, by loading
A different controller
A different template, possibly with different components and widgets
So what you would end up having is a structure with
The Tree directive on the left
A ui-view named, let's say, top
A ui-view named, let's say, bottom
Each item in your tree directive can then be a ui-sref, which is just a fancy way of saying instead of redirecting to a URL, redirect to a state.
You could then define your configurations in your application in a single place, like so:
$stateProvider.state('dashboard', {
views: {
"top": { templateUrl: 'my/dashboard.html', controller: 'DashboardCtrl'}
"bottom": { templateUrl: 'my/dashboard-grid.html', controller: 'DashboardGridCtrl'}
}
})
Similarly, you could have a state definition for each item in your tree directive, and each one just be a link to a different state.
Of course, the state definitions are done in your config section in an AngularJS application, which you would know is before the application starts. What if you needed dynamic states as well?
Well, a few answers / thoughts to lead you down the way for that as well:
The controllers and services would have to be predefined, you would not be dynamically creating HTML content and/or JS controllers
It is possible to expose the $stateProvider as a global variable in the config section, and dynamically call stateProvider.state inside a controller / service, wherever you have new state definitions.
More often than not though, the controllers and HTML remain constant, and we just need to trigger the different states with various parameters. That can easily be done by calling transitionTo function to transition to a defined state with various state parameters.
you can use $on, $emit and $broadcast to communicate among different controllers/scopes .
Please follow one of my earlier post . I have a setup a plunk . You can try out the example.
Angular Js newbie - link in a controller view that triggers another controller action
$on : setup a event handler
$emit : communicate to parent controllers
$broadcast : communicate to child controllers
To know more visit - https://docs.angularjs.org/api/ng/type/$rootScope.Scope

AngularJS - $rootScope to share data with other controllers

I have a abstract state whose controller get's data from a $resource async. and put the result in $rootScope.data.
.state('stateA', {
abstract: true,
url...
templateUrl...
controller: function($rootScope, Resource){
// Empty data so far
$rootScope.data = [];
Resource.query().$promise.then(function(data){
$rootScope.data = data;
})
}
})
Inheriting states are supposed to use that data. At the moment when the controllers from these states are resolved the $rootScope has not received yet the data.
When the Resource.query() is resolved in the abstract state controller, it updates the $rootScope.
Data attached to $rootScope async does not $digest? Why controllers that inherit from the abstract state do not see the changes after $rootScope.data is populated? Do I need to $broadcast and $on?
no you don't need to do any of those things, you just need to make sure your data gets properly updated and your watchers are properly set. on your child states you should do something like.
scope.$watch(function(){return $rootScope.data},function(){
})
this will let your controller know when the data array has been reassign. you can also use watch collection, it depends what type of modifications are you planning to do make to your array. assigning it it will destroy the array and create a new one, with a new address, but adding and removing elements it affects it in a different way. but bottom line you need watchers in this case because you are recreating the array.
other thing is, i really not recommend using rootScope for this purposes this is what services where made for. it might seem an overkill to use a service for this, but most of the time chances are you are also going to need to implement some data manipulation logic. and you'll end up creating a service anyways if you are doing it right
The proper approach is almost always to create a service or factory for shared data between controllers.

Angular docs: how can one share stateless/stateful code between controllers?

Been reading the Angular.js' Controller docs and stumbled across:
Sharing stateless or stateful code across Controllers — Use angular
services instead.
But this leaves me uncertain. How do one can share a stateless/stateful code between controllers? Or what does the "code" mean here? A model? Besides, controllers do not refer to each other, as far as I understood. Can anyone clear things out for me(others) please? Thanks.
I think what they are referring to might be one of the methods to "persist" data, sharing it between controllers or between route-changes. One way to do that is to put it in your rootScope, another is to use a service. If you define a service like this:
.factory("MyDataObject", function() {
return {};
})
Then MyDataObject will be the same object anywhere you call it, allowing you to save things into it in order to share data, functions and states between controllers (or directives, or other services, etc).
You never know with the Angular documentation, but I would guess that is what they are talking about :)
See for example this answer: Angularjs, passing scope between routes
Here is my view on subject. As angular guys have always tried to explain, scope is not your model. Angular "services" are way to do it, but word service is such and overloaded term. Coming from DDD background, I cannot reconcile word service with a state or statefulness, it just does not make sense to me. What makes more sense is ViewModel or whatever you want to call it. Since I've worked with Silverlight using MVVM pattern, I call them ViewModel. As it is a job of a "Controller" to provide Scope for a View, my controllers have been so far very lean. Bulk of logic is in a ViewModels that get associated with a View through a $scope that controller creates. Does that make sense? So my controller might take a dependency of let's say mySearchViewModel, bulk of the logic is in there and can be shared between controllers, and to associate it with a view you would do something like $scope.vm = mySearchViewModel in mySearchController.

Resources