AngularJS codes structure. Are they any difference? - javascript

New in angularJS, I would like to know what are the pros and cons between the codes below?
Which is recommended to use?
$routeProvider.when('foo', {
templateUrl: 'foo.html',
controller: fooCtrl
function fooCtrl() {
//something here
}
});
or
$routeProvider.when('foo', {
templateUrl: 'foo.html'
});
app.controller("fooCtrl", function() {
//something here
});
//in html
<div ng-controller="fooCtrl"></div>

I prefer the second approach, and use it when developing our application.
It is the elegant way of coding , seperating your routes-configuration, module-wiring etc from the Controllers. we can write the routes-config in a main file say app.coffee [I use coffeescript] defining like
routesConfig = ($route) ->
$route.when('/employees',
{templateUrl: 'employee.employeeView.html'})
Define the routesconfig and wiring modules [eg: employee.employeeController] here.
modules = ['employee.employeeController', 'user.userController']
you can create, start your angular application from here,
m = angular.module('app', modules)
m.config['$route', routesConfig]
Now you can specify the Controllers seperately, say in employeeController.coffee
name = 'employee.employeeController'
mod = angular.module(name, [])
mod.controller(name, [
'$scope'
'$log'
($scope, $log) ->
$scope.name = 'java'
In your View, say employeeView.html
<div ng-controller="employee.employeeController">
<div class ="info">
Name is {{name}}
</div>
Basically we seperated Controllers, View , application configuration from each other.

To add something specific to your question,
If you are using the first approach, then probably you are using your controller as a Route Controller, and in
second approach , it is a View Controller.
In both cases, controller will be instantiated for the mentioned route.
For instance, I have a main page index.html and i am adding many views (ng-view) in the basic html template.
If you have two different sections of view in this template say 'section1' and 'section2' and each of them are included
with ng-view, then you probably need two different controllers, and is good to define them using the second approach.
Use this type of controller to initialize the scope with data,functions,watches etc and refer the controller in your view using ng-controller.
If you have a section, say 'section1' [representing the main html page] that is included via ng-view which encapsulates both section1 and section2,
then that view needs route controller.
Do not use both the approaches for a single view/route as it would result in creating two instances of same controller
for the same route.
I like to add two links here which eloborates this (your query) and address this query (problem in defining controllers in two places)
https://groups.google.com/forum/?fromgroups=#!topic/angular/52zE0ibOAgk
AngularJS can a $on method be called more than once for a single $broadcast?

Related

AngularJS MVC Razor - How does one define a single controller in multiple files?

I have an MVC application that has a master layout that has a #RenderBody() inside of it that renders the body of the individual page. In the master layout I have given the body tag an angularjs app name and controller name.
I want the controller to be defined in a separate global angular.js file. This will share common functions that every page can take advantage of.
myApp.controller('myController', ['$scope', '$http', function ($scope, $http) {
$scope.sharedFunction = //...shared function stuff
})';
I also want to add specific scope functions and variables in the child pages in MVC. When I get to the child pages, I believe I end up redefining the controller if I use the same syntax.
myApp.controller('myController', ['$scope', '$http', function ($scope, $http) {
$scope.showOverlay = false;
}]);
How can I make it so the same controller that is defined in the body gets page specific items added to it in the child pages that are rendered using #RenderBody()?
You need to define your 'app' as a module in Angular, like so:
var app = angular.module("app", [myController])
The 2nd part of the declaration allows you to pass in an array of 'dependencies' that your Angular app relies on. In this case, your app will include your 'myController' controller
Then use this attribute on the part of your html that you want Angular to act upon:
ng-app="app"
Doing this will make your controller available to any page that utilises your 'app' module.
I got this to work by nesting ng-controllers. The second controller inherited all of the first controller functions and I was able to overwrite them and add to them in the second controller.

In AngularJS how to access multiple child scopes from parent scope

I have a parent zone builder controller which has multiple US States that can have several zip codes within each state.
Here is a breakdown of the basics of the format:
BUILDER CONTROLLER
app.controller("builderController", function($scope, $http, $rootScope, $timeout) {
$scope.zones = [];
});
ZIP CONTROLLER
app.controller("zipController", function($scope, $http, $rootScope, $timeout) {
$scope.zipCodes = [];
$scope.addZipCode = function() {
$scope.zipCodes.push({code: '', distance: '25mi'});
}
$scope.removeZipCode = function(index) {
console.log(index, 'index removing');
$scope.zipCodes.splice(index, 1);
}
});
There can be multiple zipControllers in one builderController inside of the builder controller I want to come up with an object or way to iterate through all of the Zip Controllers so that I can calculate a total distance and number of zip codes used, each time one of the child controllers is updated.
What is the most efficient way to do something like this in Angular?
BASIC GOAL
So there could be 4-5 zipController elements in one builderController I want to have a variable in the builderController called something like totalZipCodes which counts the total number of zip codes in each zipCodes array for each controller, How would I do that with a service or factory? Or is there another way?
Store the data in a factory and have the controller call the factory to do the calculations.
a general approach
As #PrinayPanday suggested in his comment, you should use something like a component/directive to do this. I'm prefacing this by saying I will be using the term directive and component interchangeably as I'm not sure of your constraints. I would achieve this by doing the following:
create a parent directive that defines a directive controller
create child directives that require the parent directive controller
when the child directive initializes, it will register itself with the parent controller
use the parent controller's list of child directive controllers to do what you need to.
You could also use the child's scope to declare a callback on some event (such as $onInit) rather than defining the directive controllers. I have answered several questions like this. So you might find these answers to be helpful in understanding the above solution more:
What is the relationship between an Angular 1.X controller and directive
Angular: Looking for an explanation on custom directive syntax
specific to your needs
As I'm rereading your question, I have to ask if there may not be a better way to solve this by sharing the data in a service/model rather than needing custom directives?

What are some approaches to reducing controller complexity in angular (with ui-router)?

I am using angular with ui-router. I have a very event driven form which corresponds to a controller which currently holds many $scope callback functions as such:
controller: function($scope, $localForage, $stateParams) {
$scope.addMaterialRow = function(){
...
};
$scope.save = function() {
...
};
...
}
What are some approaches I could take to reduce the complexity in the controller? It is getting quite big.
It might help to see more functions from your controller. Offhand, though, the obvious ones are:
Offload logic to a factory/service. This is especially convenient if your form data needs to be shared or persisted across states.
Go the more Angular 2 / React route and componentize a lot of the view by using directives. For example, turn your complex form into a directive which maintains the logic for all the events and validation on the form. If your form is event-driven, then communicating with other components should be a simple task.
Then your main view controller is sort of the traffic cop for the different directives on the view.
The one that stands out from your example is to use the controllerAs syntax. This eliminates the need to bind directly to the $scope.
As well, define your controller separately from the ui-router state configuration.
// ui-router state config
controller: "YourController",
controllerAs: "vm"
Then in a file all on its own your controller looks like:
YourController.$inject = ['$localForage', '$stateParams']
function YourController($localForage, $stateParams) {
this.$localForage = $localForage;
this.$stateParams = $stateParams;
};
YourController.prototype.addMaterialRow = function() {...}
YourController.prototype.save = function() {...}
angular.module('yourModule').controller('YourController', YourController);
In your view, you will prefix the controller actions with vm. like <a ng-click="vm.save()"></a>

Originzational MVC and Angular keeping from injecting what I don't need

My problem is I have one ng-app. Does that mean I have to do dependency injection for plugins I may not be using on that given view? Example I bring in ngTagsInput does that mean I have to do it even when the view doesn't call for it? That would mean I have to include that js for every view even if it doesn't use ngTagsInput.
I have a very large MVC .NET application and I am trying to figure out what is he best way to handle bringing in external plugins.
I have some code like so in our Main _Layout template:
<html ng-app="ourApp">
<head>
<!-- all of our includes are here -->
</head>
<body>
<directive></directive>
<anotherdirective></anotherdirective>
#RenderBody()
</body>
</html>
RenderBody is where MVC slides in our views from our mvc routing.That view may look like so:
<script src="~/Scripts/HomeAngular.js"></script>
<div ng-controller="HomeCtrl">
<directive3></directive3>
</div>
App JS:
var app = angular.module('ourApp', ['ngTagsInput']);
IS there a way I can get around having to inject ngTagsInput on every view page even if i don't need it?
There are several different ways to handle Dependency Injection (DI) in angular. In this first example, you simply define ngTagsInput before declaring the controller. If ngTagsInput is a service, for example, you'll need to return an object with methods that allow you to access the data inside of that service.
For example:
app.service('ngTagsInput', function($scope) {
var data = {};
return {
getData = function() {
return data;
},
setData = function(val) {
data = val;
}
};
});
app.controller('HomeCtrl', function($scope, ngTagsInput) {
// ...
$scope.tags = ngTagsInput; // whatever you want to do with it
});
However, there's a problem...
In the example above, if you run that code through a minifier, you'll get $scope turned into some variable (a, b, x, etc...) and angular wont know what to do with that.
In this method, we use an array. The last item in your array is your lambda function for the controller, which takes 1 argument for each previous item in the array:
app.controller('HomeCtrl', ['$scope', 'ngTagsInput', function(scp, ngTagIn) {
// ...
}]);
This code can be run through a minifier just fine, since the dependencies are strings in the array and can be renamed to anything you want inside the function's parameters.
DI also works in directives, factories, filters, and services with the same syntax; not just controllers and modules.
app.directive('HomeCtrl', ['$scope', 'ngTagsInput', function(scp, ngTagIn) {
// ...
}]);
Couldn't you break down your application further into smaller modules instead of just one. Then you can inject the smaller modules into the app module and only inject the ngTagsInput dependency on the modules that actually need it. That's how I typically break up my application by function or area.

Angularjs - dynamic pages, same template, how to access and load article by id

I am slightly puzzled on how to use angularjs to build a blog-like web site.
If you think of an ordinary blog,,, and say,, I am building it using php and mysql.. what I don't understand is how do I make angular get an article based on id..
I can load data for a list of all articles.. I can load data for a single page (from a static json),, I understand how to send http requests,, but how do I access
mysite.com/page?id=1 or
mysite.com/page?id=2 or
mysite.com/page?id=3
Obviously, I want to load the same template for each separate blog post.. but I have not yet seen a single example that explains this simply.
If I have three posts in my database with id 1,2,3 how is angular meant to generate links to each individual article? I understand that I can load data to assemble urls but what urls? I suppose I am confused with routing.
Could you recommend a SIMPLE and understandable example of this? Could you suggest how to think about this?
Thanks!
In this short explanation I will use examples based on official tutorial.
Propably somwhere in your application you created controllers module with code close to that:
var blogControllers = angular.module('blogControllers', []);
// other controllers etc.
blogControllers.controller('BlogPostCtrl', ['$scope',
// more and more of controller code
We will be back here in a moment :) If you have controllers module, you can create a route linked to the specific controller:
var blogApp = angular.module('blogApp', [
'ngRoute',
'blogControllers'
]);
blogApp .config(['$routeProvider',
function($routeProvider) {
$routeProvider.
// other routes
when('/post/:postId', {
templateUrl: 'partials/blog-post.html',
controller: 'BlogPostCtrl'
}).
// other...
}]);
Well but what we can do with this :postId parameter? Lets go back to our controller:
blogControllers.controller('BlogPostCtrl', ['$scope', '$routeParams', 'BlogPost',
function($scope, $routeParams, BlogPost) {
$scope.post = BlogPost.get({postId: $routeParams.postId});
}]);
As you see, we are passing $routeParams here and then our BlogPost resource (it will be explained). Simplifying (again), in $routeParams you have all the params that you put in the $routeProvider for exact route (so :postId in our example). We got the id, now the magic happens ;)
First you need to add services and/or factories to your app (and look, we are using ngResource):
var blogServices = angular.module('blogServices ', ['ngResource']);
blogServices.factory('BlogPost', ['$resource',
function($resource){
return $resource('action/to/get/:postId.json', {}, {
query: {method:'GET', params: { postId: 'all' }, isArray:true}
});
}]);
Now you know what is our BlogPost in controller :) As you see default value for postId is "all" and yes, our api should retrieve all posts for postId = "all". Of course you can do this in your own way and separate this to two factories, one for details and one for list/index.
How to print all of the blog names? Quite simple. Add list routing without any special params. You already know how to do this so let's skip it and continue with our list controller:
blogControllers.controller('BlogListCtrl', ['$scope', 'BlogPost',
function($scope, BlogPost) {
$scope.blogPosts = BlogPost.query(); // no params, so we are taking all posts
}]);
Voila! All posts in our $scope variable! Thanks to this, they are accessible in the template/view :) Now we just need to iterate those posts in our view, for example:
<ul class="blog-posts">
<li ng-repeat="blogPost in blogPosts">
{{blogPost.title}}
</li>
</ul>
And this is it:) I hope you will find AngularJS quite easy now!
Cheers!
I think what you want to use for this is $routeParams. Have a look at this video from egghead.io which explains how to use it:
http://egghead.io/lessons/angularjs-routeparams
It's a good practice to use hash navigation. So your routing should look like this
mysite.com/blog/#!/id=1
mysite.com/blog/#!/id=2

Categories

Resources