Say I have two views that share a controller. Both views use the ng-route service. If a scope variable is changed in one view and then you switch to the second view, how come the second view doesn't update?
Example: My controller has a variable that = "hello". I output this variable just fine in both views. In view one I have an onclick that updates the variable to say "Whatsup". That works fine, but after the event I switch views and the second view is outputting "hello" still. Is there a way to share these? If not, then what is a technique to share data?
I'd like you to know that AngularJS is designed for SINGLE PAGE APPLICATIONS (SPA) so this behavior is not supported by the framework.
Each view have a different scope even though they share the same controller. So updating a scope variable for one view won't update the other.
If you want this behavior, I suggest using $on to listen to events.
Also, on your code you have $scope.test = 'hi'; that is hard-coded on your controller with no conditions or whatsoever which is why it reflects on both of your views who share the same controller.
Best practice is to have one view per controller. As your site scales, it would get very hard to manage multiple templates/views with one controller.
A service is the way to share data between controllers.
For your example, you could have a activate functions that are called when each view is rendered that gets the updated variable from the service you inject. Your on lick function should save the variable to the service to make it available across controllers.
Related
I am new to angularjs. I have designed an angularJS service, which is as per the diagram given below :-
Global Service is used as a mean for inter-controller communication. That's, it contains data shared between parent and child controller. Grand Parent controller opens a popup dialog which has parentController2, which in turn open another popup, which has childController3.
Now, What I want is, data stored in global service must be set to null, when its associated controller is destroyed. It's because services are singleton in angularjs, as per my knowledge. So, I don't want service to hold variable throughout the life-cycle of application, even if they are not required.
Moreover, I am using controllerAs syntax and don't want to use $scope(I know that I can do garbage collection in '$destroy' event on scope), to make my stuff compatible with angularjs 2.0.
Is there any way, I can garbage collect variable in service, which are not required, from controller, when controllerAs syntax is used ?
Apologizing for newbie question. Thanks in advance.
using ng-view is one more solution over here for garbage collection as it destroy's the scope as soon as view is changed. It will be used with ngroute but still provides better mechanism for garbage collection.
You can check the ng-view code
function destroyLastScope() {
if (lastScope) {
lastScope.$destroy();
lastScope = null;
}
}
This function is called inside the directive that destroys the scope of the previous scope i.e if you go from parent to child the parent scope will be destroyed
The Goal
What I'm trying to achieve is using a service* to hold the single source of truth for my directives. I realize that I can use API calls, but the problem with that is that the app I'm working with is slow enough (I'd change that if I could) it doesn't need extra calls. Plus, that wouldn't keep changes synced as changes are made to the data throughout the app unless I saved the data with every single change. I would like to do something like this from controllers and other services:
function SomeController(['DataService', function() {
var dataToCollectWithoutAPICall = DataService.currentData;
}]);
function SomeService(['DataService', function() {
var dataToCollectWithoutAPICall = DataService.currentData;
}]);
That way when a service or controller updates the currentData it updates for the others as well.
EDIT:
Should have said 'updates the controllers/services within that instance of a directive'. So updates to <directive id="first"/> shouldn't update the data for <directive id="second">. However any changes to data for <directive id="first"/> should update the data for all controllers/services within <directive id="first"/> only;
The Problem
This works great if you only have one element using that directive, however if you have a second element then one directive can update the service and the other directive's data is updated as well.
From first directive:
DataService.currentData = 'First Data';
Then second directive updates this:
DataService.currentData = 'Second Data';
All of a sudden the first directives dataToCollectWithoutAPICall is 'Second Data'.
I'm avoiding putting the data on $scope because services can't use the $scope and then the service is no longer the single source of truth.
The Questions
Is it possible to isolate the data for each directive?
Is there a unique identifier for each directive in Angular that controllers/services know about?
Does anyone know a way around this?
One idea I would be willing to use is creating a unique identifier for each directive, e.g. DataService.currentData['UniqueIdentifier'].
I've also considered using local storage, but the browsers that I have to support don't all use local storage and I would run into the same problem of one directive overriding another's.
I'm willing to completely re-think the way I'm going about this. I just want a SSoT that all controllers/services can pull data from.
* I'm using services to mean either services or factories.
i'm very confuse about how ember controller works.
I'm starting with ember and ember-cli now, and i would like to understand more about how controller works.
If i have an nested route called new, inside a events resource, i should i have:
models/event
routes/events/new
templates/events/new
What about controllers?? I just work one simple controller, or should i use controllers/events/new too?
There isn't any generator command that will create every resource for me? I need call one by one?
Thanks.
What about controllers?? I just work one simple controller, or should i use controllers/events/new too?
This mainly depends on what is your controller needs to do. If it's only the essential stuff the controller does anyways, Ember will create that controller under the hood for you and automatically bubble actions up to its parent controller.
No better place than Ember guides to read what a controller is used for:
The simplest definition is:
Controllers allow you to decorate your models with display logic.
This means that you basically use them as the main communication layer between your route and your template. Essentially, you model comes from your route, through your controller and into your template. Actions happening in the template go up to the controller and then to the route. Therefore, controller is essentially the middle layer where you user your model (and other data) to control what is shown to the user, control what a user can do, control where can they navigate etc.
However, be aware of the plan for the future:
Controllers are very much like components, so much so that in future versions of Ember, controllers will be replaced entirely with components. At the moment, components cannot be routed to, but when this changes, it will be recommended to replace all controllers with components.
This means, that right now, controller responsibility is limited to two things:
Maintaining application state based on the current route
Handling or bubbling user actions that pass through the controller layer when moving from a component to a route.
All actions triggered on a template are first looked up on the controller, if it is not handled or bubbled (by return true) in the controller, they are looked up on the route.
Therefore, controllers for your /events or events/new routes aren't necessary at all, only if you want to handle things happening on those routes right away (in a smaller scope) instead of allowing everything to bubble up to the ApplicationController.
There isn't any generator command that will create every resource for me? I need call one by one?
Yes. Since, if you don't specifically create a controller, Ember just generates one for you behind the scenes. You need to specify where you want to handle things yourself.
You should visit the link I gave above (or here it is again) to the Ember guides that have many more examples in much more detail.
I'm using user contributed modules that I am trying not to edit so that upgrades are nice and easy.
I'm attempting to allow a user to browse to a CSV File on the local filesystem, parse it and display it in a dynamic table. To do this I'm utilizing PapaParse, ui.grid and angularFileUpload.
The problem I'm running into is that they all work at different levels at the hierarchy.
angularFileUpload is nice an easy - it calls a function in my controller (using controllerAs syntax). That function then runs a PapaParse function to convert the CSV file to a JSON Object (all working so far).
The problem I have is that ui.grid works on the $scope object since it's a attribute directive and doesn't support watchers to monitor for changes to a variable (you have to call a function on data update to re-bind the data).
So the question is, from within my controller whats the correct/recommended way to communicate with an external directive without editing the directive to listen to messages.
ui.grid should bind to changes of its associated data. Therefore you should only change your local $scope, to which the grid is also bound, and everything works fine.
As you mentioned, directives do not listen to messages, but that's is also not how Angular works. Angular forces data-binding, so by binding a field into the directive, the component should take care of updating its presentation, as soon as you change the model you bound it to.
Unfortunately, ui.grid does not adhere to this convention. Therefore you have to render the grid as soon as you user's data is there (inside the function that is called after opening the file or via $watch). This can for example be done via ngIf, where the child directive is only loaded when a field is true. When the user switches between two CSVs, you could set the value to false, load the data in your model and set it to true again. Be sure that there is one digest cycle (e.g. via $timeout) in between so that your change affects the UI.
Let's say we are implementing CRUD operations for a specific object - those view would be very similiar and i think i should use the same view with multiple controllers. Is there a way to choose the controller dinamicaly based on a parameter or this type of action can be only taken inside the controller?
You technically can, but according to the exellent angular styleguide from Johnpapa, style Y037 :
Define a controller for a view, and try not to reuse the controller
for other views.
Though, you're actually right thinking that some CRUD logic should be made common and abstracted. Controllers are just not the right place; Factories (ie services) are.
You can use the same view on different controllers but it depends on what you are doing inside the view and whether or not the controller has the necessary members within the $scope object that are bound in the view. You can add an "action" variable on your $scope object and modify the view based on the same.