I have a service which stores certain object to share it between different controller. In this case I have the following code
$rootScope.$on('controller.event', function(event, arg){
self.backendConnectorService.getBackendObject('99901').then(function(object){
if(object) {
self.myService.selectDeselectObject(object);
console.log(self.myService.getCurrentObject());
$state.go('myApp.mainArea.appsArea.objects.wizards');
}
});
When I have my object I go to that state that will need the object initialized. The problem is that when I load the controller for that state, when I do self.myService.getCurrentObject() returns null. When I execute the console.log in the above code I'm getting the correct object. Why is this? I thought that services were singletons.
If you're trying to preserve data between states, you need to think in terms of using the built-in angular router or the 3rd party UI-Router (very popular, which I prefer). Then you can use resolves to resolve injections, or params to pass data along from one 'state' to another.
You're getting your 'object' then moving state - this initiates another controller, losing your object. Look at scotch.io's angular router page, which is quite helpful. You'd be better off using resolves in the state.config.js, then injecting it into your controller to use.
Related
I have to add functionality to an existing AngularJS application. I need to be able to pass an additional parameter to potentially any route of the angular application. (It's an email tracking ID)
I would like to use a querystring parameter if it's possible, without affecting the existing routing. Then have some code somewhere that checks for the querystring parameter (not sure about this part, some kind of global navigation listener?).
I'm not super familiar with angular. Do i need to mess with the routing and mess with code in the controllers, or is there some way I can code one global service to parse the querystring parameter regardless of the route?
I know I could create a service that uses $location to get the querystring parameter, but I would have to inject that service into every controller which seems kind of redundant.
Since this is an email tracking id I'm assuming that you just need to grab it once when the user first enters the site. It also looks like you're not looking for a super deep solution, so I'd suggest just grabbing it where the main module (your app) is first created and storing the tracking id as a property on your app.
There is a $locationChangeStart and $locationChangeSuccess event that fires on the $rootScope that you can bind to in a run block somewhere if you want to grab a query string from the route every time the page changes.
But if you're trying to keep track of that value throughout your entire application, once you get it from the server, you could store it on a service and inject it wherever you need it in your application. If you're trying to avoid injecting dependencies into your Angular app, then you're only going to hurt yourself, especially when it comes time to write tests. Your controllers shouldn't depend on things that aren't provided through your application's injector.
Use $location. It adds hashed query string params like "example.com/#?myParam=value"
Get query string params:
$location.search(); // gives you an object of params
Set query string params
$location.search('myParam', 'value'); // one at a time
$location.search({ // or pass an object
'first':1,
'second':2
});
Just be sure to inject $location in your controller/directive.
I have an app with two controllers where I want a change in one controller to affect (different) data stored in the other. tl;dr when I remove a category from the first controller, I want to edit any items in the second controller with that category, so that they will now be category-less.
As far as I can tell what I want is to use a service, but I feel it would be simpler if there were a way for me to simply edit the data inside the controller scope. So my questions are:
Is there a way to simply edit controller data or call controller methods from a service?
Otherwise, is it reasonable to store the latter controller's data in the service, even though the former controller only needs access to change it? How do I reference this data for the purpose of doing ng-repeats?
Edit: to clarify the data is a set of json objects which contain data for each category and each item, and the web page contains ng-repeats to go through and list each of them. I have a number of functions which edit both lists of data, and I want changes to one list to make changes in the other.
Your idea was correct, you should put all your business logic, including data that needs to be consistent between different parts of your application, into services. controllers should only manage the view and connect the data to it.
Keep in mind that services are Singletons - there is always only one instance of each service, holding your data.
To answer your question: I would argue that storing data in a service instead of a controller is always reasonable when it works (aka when the data is not specific to one of multiple views, but consistent throughout the current application state), and giving access to that data to manipulate it is perfectly fine - even better would be to put the manipulation logic into the service itself (or another service only for that) and to just let the controller connect to a call invoking that.
There is an article by Todd Motto on that topic (thin controllers)
I think it will be better use events for this purpose. In your first controller you can published the event on category deletion like below.
$scope.deleteCategory = function (category) {
$rootScope.$broadcast("categoryDeleted", category);
}
Then you can observe this event in any controller like below in second controller you can listen categoryDeleted event.
$scope.$on("categoryDeleted", function (event, category) {
// do whatever you want
});
Do not call controller directly from the service, this is a bad practice, not only in AngularJS, but in most languages frameworks.
The problem you have described ("a change in one controller to affect (different) data stored in the other") is a problem of communication between components. You can solve this issue with events, thus there is no need to move data from the second controller to the service.
Let's consider some example:
http://jsfiddle.net/simpulton/XqDxG/
When you click on the LOG button the this.broadcastItem() is invoked, and the 'handleBroadcast' event is broadcasted.
Other constrollers, controllerOne and controllerTwo, handle this event:
$scope.$on('handleBroadcast'
and do the things they want to do.
So, in yor case, you can introduce the 'categoryRemoved' event, and broadcast this event in the first controller. Once the event is broadcasted, your second controller handle it and edit its items.
Also you should pass the removed category in the event (instead of 'msg' in the example), so that second controller has to aware which exactly category has been removed.
In way you want to do that, $rootScope can be used (shared across controllers - modyfing in one, accessing in another), but its generally bad idea. Im not sure if I get it right but its typical situation when you actually need service with controlling some external data.. Its some static json you want to modify? Can you specify it more clearly ? :)
I have a repeated set of API calls in an Angular controller.
The relevant data is of course the API URI, POST or GET, some header data, and JSON objects. The API call always returns a JSON object.
I started to use a Directive but that seems most relevant for data that is used with $scope (e. g. in the View). This data runs under the radar and might eventually generate data used in the view but most usually not and most usually not in a way that can be abstracted.
So: Does this mean I shouldn't use a directive? If I don't use a directive, would it be better to use a JS Object (seems more modular) or Function (seems more variable friendly) to handle this code?
Yes, I get that objects can contain functions, but functions can also contain callbacks so...looking for kind of a "best practices" here. In terms of modularity and flexibility.
You should create Angular service for that.
https://docs.angularjs.org/guide/services
Your service will contain a method, lets say "getResults" which will make an API call and return either data or a promise ($http). Then you can inject you service to your controller and use that method to get the data and assign it to $scope.
An Angular service is certainly preferred to a more general JavaScript one because it allows you to take greater advantage of Angular's scope and other such things. Between Angular's Factory, Service, and Providers, a Service is the most in line with what you're trying to do since a Factory is too basic and generally used to solve smaller problems while a Provider is used -- as it says in the Angular docs -- "only when you want to expose an API for application-wide configuration that must be made before the application starts." Which is not what you're trying to do.
I just need to use the res.render function at some places but it is not passed to the callback I am using. Isn't there somewhere a global version of the render function or is there another way to access this?
In Sails v0.10.4 there is
sails.renderView(viewPath, options, callback);
Also, when rendering emails, you probably don't need to use a layout. So before calling sails.renderView, add
options.layout = false;
You don't need it at all places, really.
res is a response object and it makes sense only in controllers, because only controllers deal with request handling and response rendering.
Do you want to use res.render from models, services? Maybe it's because you think that all your code is always in we_have_request_and_user_is_waiting_for_response state.
Well, It's not true: model methods and services can be called from sails console, or from background workers, or from code, than runs by schedule. In these cases we don't have res object at all.
Controllers are place specially designed to contain user actions responding logic. So, you should place that logic in controllers. MVC
Technically, previous speaker is somewhat right: there is a reason res exists only within controllers. For example, what if it's a CLI application, and there's simply no request/ response in HTTP-meaning?
That said, if you just need to render some HTML for one or another purpose, you can always use global Express' renderer, which doesn't require response to be presented: it's accessible via sails.express.app.render, see Express' documentation for the method's params.
I have the simplest possible Ember app in this JSBin. All I'm trying to do is find a model. Based on other SO questions, I've tried the following.
App.User.get('store').find('user', 1);
App.User.Store.find('user', 1);
I've defined App.Store, but App.Store returns undefined in the console. I'm obviously missing the absolute most basic concepts of Ember models. Explain like I'm 5, please? I literally just want to return a user object and call a property on it.
The store is injected to routes/controllers. Inside a route/controller you can use this.store.find('user', 1) to fetch a model. But there is no global access to the store.
http://jsbin.com/aYIkAcUk/6/edit
If you feel guilty about touching the innards, which you should a bit, do not read on.
For transparency sake, you can get the store globally. After the application has initialized and is ready you can use the innards of ember to fetch it using the container lookup method. (If you need to know when the app is ready you can use the application ready hook.
var store = App.__container__.lookup('store:main');
var user = store.find('user', 1);
http://jsbin.com/aYIkAcUk/7/edit
As of Ember Data 2, the data store is now handled as a service. Thus, to look it up globally, the statement is now:
App.__container__.lookup('service:store')
Where App is the name of your Ember application. Kingpin2k's answer will not work with Ember Data 2.