Global querystring parameter - javascript

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.

Related

Service get object null after init

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.

How can I pass json object from one page to another page

I'm trying to pass a json object just after redirecting to another page,
The problem is when I use $scope.data in order to save client, the problem is that after making the redirection the $scope.data is empty again
testProjectApp.controller('ClientController',
function EventController($scope, clientList, $window, updateClient){
$scope.editClient=function(client){
$scope.data=client;
$window.location.href = 'ClientDetails.html";
}
the controller is working on two pages
It depends on if you only want to use angular specific APIs or general methods are also acceptable. Consider the followings, which one better fits your situation, you may need to serialize/de-serialize the json object:
Some options:
Cookies
Session Storage
Local Storage
Use Url to pass the parameters
If it is a single page application, then you can just set it to a variable in a Service, and inject that service the controllers need the var. Basically a get, set
It would be a good idea to figure out the size of the json, and are there any limits and constraints first, then choose the suitable method.
Angular is used for SPA's - single paged applications. As soon as you redirect to another page, a new scope is created. I used local storage - here I asked and answered my question in reference to it - AngularJS help sharing data between controllers using $broadcast
So to be honest, this is a duplicate.

AngularJS - accessing elements inside a controller from a service

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 ? :)

Angular: How to go about refreshing service data

I am fairly new to Angular and trying to build an Angular application.
I have a lot of data that needs to be used by multiple controllers throughout the app. As I understand it, that is the perfect situation to use a service.
I am planning on storing this kind of data in services. For example I plan on having a users service which all controllers that need user data will inject.
I would like the users service to hold the master list of users and any controller that needs users to just use the one instance of service list.
I am having trouble envisioning the pattern though. I mean:
1) What is the standard way of having the service refresh its data from the server? I realize that I could just go and request the entire list of users every 10 seconds from the server but that seems kind of heavy weight...
2) Ideally I would like to be passing around only a single instance of each user. This way if it gets updated in the service, it is sure to be updated in all of the controllers. I guess the other option is to have the service broadcast an event every time it updates a user? or to use watchers?
3) What is the pattern by which the controllers interact with the service and filters? Do the controllers just request data from the service and filter it in the controller? The other option is to have the service do the filtering. If so how do I communicate the kind of filtering I need done to the service?
I think that by using some kind of solid pattern I can take care of alot of these issues (and more that I am sure will arise). Just looking for advice on some common patterns people employ when using singleton services.
Thanks in advance.
Answer to point 1. A service is just a singleton. How you store and refresh data into it has nothing to do with its nature. Not sure why you want all user data inside a service (unless you are building a user management app), but you could use several techniques like polling (eg. using $timeout ask for new users and append them to the existing ones) or push (eg. socket.io/signalR which will push you the payload of new users when available). This can be done both inside the service itself or by a controller that will add/remove data to the service (eg. a refresh users button in the UI)
Answer to point 2. You can bind/use the reference of the data inside the service directly into your controllers using a getter so that changes to the data are shown instantly (given that are two way binded, if not use events).
Answer to point 3. You can apply filters inside the controllers or in the view it self (not recommended). You can also have a function in the service where you pass the filter or filter params and get the filtered copy of the users collection back (since you will be using the users collection directly in many controllers at once you shouldn't modify that, unless that's desired). If you are reusing the same filters again and again across the controllers you can have a function for each filter that returns the filtered collection with a "hardcoded" filter. You can even have helper function in the service to help you assemble complex filters or have multiple copies of the collection already filtered cached(if you find you are using the same filter again and again)

Calling into or between controllers in AngularJS

I have some fairly complicated logic in a bootstrap dialog which I've moved into its own controller for isolation.
There are times I want to launch the dialog or call a function in the controller based on some logic that occurs elsewhere in the app - in another controller, or a service. I've achieved this by adding an id to the ng-controller element then looking up the element by that id, and calling things off the .scope() of that controller. Essentially this:
In html:
<div id="modalController" ng-controller="modalController">
And in another service or controller:
angular.element("#modalController").scope().somefunction()
This seems pretty weird that I can't just get a controller by name. Is there a way to do this?
Create a service and bind the model to data maintained in that service. Make a change to the model within the service and it's made everywhere.
You could also create a service that provides a pubsub interface to the changes you need to make.
Yet another way to do it would be to have a single model representing the state of your system and modify that. Attach the relevant parts of that model to the scopes of each widget as necessary and you have a communication device built in.
It sounds like you are making a change in one place that should cause a change in another place. If that's the case, I'd argue having a service that updates all parts of the model correctly is the best way to go. Always imagine what you'd do if you added another widget that hangs off this functionality.

Categories