I am quite new to to angular and most things and concepts are completely new for me.
I am working on a page that have a URL as follows:
http://domain/araneum/page/show/1
Is there any easy way to read the '1' from URL?
What I was able to understand there are two ways:
Read it on backend and create JS variable to be used by angular (not sure if that is the best practices)
Pass the parameter as hash. in my case it is not that convenient, because this page is quite complex already and I wanted to have a separate application for it. Also, there are couple of validations that must happen on backend before page rendering.
Is there any other better approach?
Thanks,
I recommend completing the AngularJs tutorial if you haven't already done so. In particular look at https://docs.angularjs.org/tutorial/step_07
Relevant code for you
phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams',
function($scope, $routeParams) {
$scope.phoneId = $routeParams.phoneId;
}]);
In this example the phoneId will be in place of 1 in your URL.
Related
.factory("user", userService);
function userService($q, $http) {
function User (){
//....
}
return User;
}
or
.factory("User", ["$q", "$http", function ($q, $http) {
var User = {
//....
}
return User;
}])
I often see both depending of the situation (or rather depending of the author), but I've been wondering for quite a long time now (since I've begun learning Angular), what makes it different, and if I can use one or the other without changing anything. I usually use the first one and following the logic because I find it easier, and because I'm confused with the second one. I may have made mistakes but that's why Im asking for some help. Thanks !
The second code snippet in your question is the one that I'd recommend you to use for all your angularjs services.
Angular framework offers Dependency Injection (DI) feature out of the box that can be used when defining components such as services, directives, filters, animations or when providing run and config blocks for a module.
If you define the dependencies without using an array of string in your angular app, then you are doing it wrong. This way of registering the dependencies will work well for non minified version of the JavaScript source file.
But if you intend to minify the files for production, which everyone must, then all those (dependency) arguments will be changed to something really random which angular will not be able to map to any registered component. So ultimately, an error will be thrown by the framework.
To avoid this mistake, one can just make sure to always use an array of type string to instruct the dependencies. Read this in more detail. If you are your own then you can maybe keep this tip in mind. However, if working in a team, it is good to configure this using the options below so that everyone in the team follows this. If not, then they will encounter an error.
I'd recommend you to use strict DI mode.
How to enable strict mode?
This mode can be enabled using two options as mentioned below.
Option-1:
<div ng-app="myApp" ng-strict-di>
<!-- your app here -->
</div>
Option-2:
angular.bootstrap(document, ['myApp'], {
strictDi: true
});
Learn why is strict DI mode good for your AngularJS app in my blog post.
The first form will not work with minification. The second form is required when minification is used. The reason for this is that the AngularJS injector uses the function parameter names to resolve the $q and $http dependencies in the first form. If the function parameter names are changed (e.g., by minification), that will fail. The second form relies on the strings "$q" and "$http", which will not be changed by minification.
This is discussed in step 7 of the AngularJS tutorial.
I'm new to Angular and I guess this question may already have a fair few comments however I'd like to know what experienced Angular developers find the best practice on how to handle:
Passing data between pages (assuming each page has its own controller).
So the 3 ways I can see:
1 - In the URL parameters (I don't prefer this - doesnt give great flexibility, also in my opinion doesn't look so good)
2 - Create a service (e.g. as described here AngularJS - Passing data between pages)
3 - Using parent '$scope'
Thanks.
Most of the time you will want to use FACTORY because it has:
ability to use other services (have dependencies)
service initialization
delayed/lazy initialization
Factory example (Fiddle)
<div ng-app="myApp">
<div ng-controller="FirstCtrl">
<input type="text" ng-model="Data.FirstName"><!-- Input entered here -->
<br>Input is : <strong>{{Data.FirstName}}</strong><!-- Successfully updates here -->
</div>
<hr>
<div ng-controller="SecondCtrl">
Input should also be here: {{Data.FirstName}}<!-- How do I automatically updated it here? -->
</div>
</div>
var myApp = angular.module('myApp', []);
myApp.factory('Data', function(){
return { FirstName: '' };
});
myApp.controller('FirstCtrl', function( $scope, Data ){
$scope.Data = Data;
});
myApp.controller('SecondCtrl', function( $scope, Data ){
$scope.Data = Data;
});
Using $broadcast
You can also use $broadcast to pass data from the high tier of your controller to the end.(Example: jsFiddle)
No 2 is the most preferable way as I always use that in my projects
2 - Create a service (e.g. as described here AngularJS - Passing data between pages)
This is the most Angular-ish way and as you've pointed out, is recommended by their docs.
But there are a few things to ponder, much of which is dependent on a) your development experience and b) what development paradigms you're used to. As a bit of background, I came from a very Java-ish background (I was a Flex/Actionscript developer for nearly 10 years). Many of the typical Java-esque development paradigms do not manifest themselves clearly in Angular. Angular seems to me to come from a more Ruby-like paradigm. This is exemplified in many of their APIs and usage recommendations.
One thing I've found out is that rolling your own solution to bypass some of the things that may be distasteful to your development proclivities is often more work in the long run. I can give you about 6-7 examples (in the comments if you wish) in which my inexperience in using Angular and my hardheadedness in being an experienced developer ended up with me finally refactoring to be more Angular.
So to recap, in the case of construct-to-construct communication, I'd go with option #2. I'd elect for an event bus as a secondary option only if the recommended option doesn't suit your needs.
It depends on what the data you are passing is for.
If there is some data that determines that state of your controller and should be linkable by users, e.g. you have a page that displays a blog article and it needs an ID to get the article info from a database, then that id should be a url parameter e.g. /blog/:id.
If you need some data that belongs to the parent controller, e.g. you have a blog article page and a child part of that page is an author panel that needs to get some information from the blog object itself, then you could access that via the parent $scope, however you should note that this tightly couples the author panel to the blog article controller, and it is almost always a better idea to create a directive and pass the blog object in to the directive isolate scope.
If you have some global data, e.g. a logged in user has a language setting which needs to be accessed by all pages, then you should use a service.
If you need some data that is to do with an event, e.g. a user clicks something and a directive somewhere else needs to know about it, then you can use $emit or $broadcast
If I have a specific route parameter that is always being passed as a query string, is there a difference between retrieving the param using angular's $routeParams service and using its $location.$$search service? If so, is one preferable to the other?
URL: //localhost:80/app/profile?id=42
$routeParams approach:
app.controller('ProfileController', ['$routeParams', function($routeParams) {
console.log($routeParams.id);
}]);
$location approach:
app.controller('ProfileController', ['$location', function($location) {
console.log($location.$$search.id);
}]);
I am already injecting $location as a dependency in the controller that needs to perform the behavior detailed in the question. Additionally, the controller's module does not yet have a dependency on ngRoute.
If your route is of type:
when('page/:id')
then using $location search won't give you the ID in the search result. But $routesParams does.
But in case of query params ex:
when('page?key=value&key2=value2')
In this case, you can go for any of $location.search or $routeParams.
It also seems that the $location way is faster in some sense (which is only natural, since $routeParams uses $location to get its values).
To explain:
My site has a mode that's only meant to be used by kiosk tablets, whereas the normal use case is customers using their own devices. To differentiate, I initiate kiosk tablets by going to https://mysite.url/?kiosk, which triggers this (which runs on load):
if($routeParams.kiosk){
$cookieStore.put("kiosk", true);
}
Now, this tended to fail, since $routeParams hadn't had time to become initialized that close to load. Switching to
if($location.search().kiosk){
$cookieStore.put("kiosk", true);
}
mitigated that issue.
(My site is currently stuck on Angular 1.2.19, and was not put together by people who had all current best practices in mind. My example may or may not be relevant to modern projects coded by competent developers ;-) )
I have an Angular application. Its working good, but as my application is getting bigger I'm worried about the large number of dependencies that I have to inject in each controller.
for example
app.controller('viewapps',[
'$scope','Appfactory','Menu','$timeout','filterFilter','Notice', '$routeParams',
function($scope,Appfactory,Menu,$timeout,filterFilter,Notice,$routeParams) {
//controller code..
}])
I am sure that the list of dependencies are going to increase in future. Am I doing something wrong here? Is this the right approach? What is the best way to effectively handle this?
It's hard to be specific without an exact use case, or seeing the exact code in your controller, but it looks like your controller might be doing too much (or might end up doing too much as you add things later). 3 things you can do:
Delegate more of the logic to service(s) that are injected in.
Separate out into different controllers, so each only has (just about) 1 responsibility.
Separate out into directives, each with their own controllers and templates, and allow options to be passed in, and output given out, via attributes and the scope option of the directive. This is often my preferred option, as you end up building a suite of reusable components, each with a mini-API.
It is fine for directives to be used like this, at least in my opinion. They aren't just for handling raw Javascript events, or accessing the DOM directly.
I've been playing with the idea of bundling services based on controllers.
So in your example you'd refactor your; AppFactory, Menu, filterFilter and Notice services into a single service e.g. ViewAppsServices.
Then you'd use your services like ViewAppsServices.AppFactory.yourFunction().
As I see it that way you can at least shift your injections into another file cleaning your controller up a bit.
I think readability would suffer a bit since another developer would then have to look at bundles rather than the controller itself.
Here's a JSFiddle I put together to demonstrate how it would work; this is how I'd imagine yours would work.
.service('ViewAppsServices', ['AppFactory', 'Menu', 'filterFilter', 'Notice',
function (AppFactory, Menu, filterFilter, Notice) {
return {
AppFactory: AppFactory,
Menu: Menu,
filterFilter: filterFilter,
Notice: Notice
};
} ])
Try to move as much logic as possible to services, even just make controller methods act as "routing - passing through" methods . After time you will see it very usefull if you will want to use similar methods in other controllers/directives. Anyway, 7 injections is in my opinion not much :)
(edit: see the comment of Matt Way below)
Also, a tip - in newer versions of Angular you don't have to write this array, just:
app.controller('viewapps', function($scope,Appfactory,Menu, $timeout,filterFilter,Notice,$routeParams){
//controller code..
}])
My approach is to use $injector, when there are lots of dependencies:
app.controller('viewapps', ['$scope','$injector',function($scope,$injector){
var Appfactory = $injector.get('Appfactory');
var Menu = $injector.get('Menu');
//etc...
}]);
The advantages:
Code can be minified and obfuscated safely
You don't need to count the index of the dependency, when you declare dependency as a function's parameter
I have an existing angular project that has something really weird with the controller. It looks like the following.
app.controller('AppController', ['$scope', function ($scope) {
var app = app_application;
angular.extend($scope, app);
$scope.itTransports = app.state.itTransports;
}]);
I have a proof of concept for something I am trying to do on this fiddle and an attempt to mix the above controller and my concept in this fiddle but I cant seem to get it to work. I think it is something to do with the weird way the above controller works but I cant break it too badly and cant talk to the previous developer. I would think that if a combination cant be done then I would need some way for one controller to call another one but I want to make sure before I go down that path.
Edit: My main goal is to add functionality to check if the cookie exists. I am trying to do this in the same controller just for simplicity sake, but like I said before I am not adding a new one.
If you have some common functionality that you want to access from multiple controllers (e.g. checking if a cookie exists) then you should put that functionality into a service and inject that service into both controllers.