AngularJS: need a best practice for hierarchical data - javascript

I am new to Angular, watched a number of videos and read docs, but not sure for i have it all compiled in my mind. I've seen a bunch of small simple pieces of code but never saw something complex. Do you know of docs/tutorials/examples to help me implement the following?
I want to make a SPA forum web application. The forum consists of numerous topic groups, each of which has topics inside, and each topic has multiple comments.
So this is a hierarchy of nested entities like this: Forum -> Topic Group -> Topic -> Comment.
In my SPA I'll need to CRUD any of them or load from server either a single entity (say Comment) or a complex view (a topic with all comments) depending on what user/admin wants.
I can't find an example dealing with the complex hierarchies. Should their controllers and models be nested or separated? How should I separate their CRUD methods? Do I put them all into the top level of $scope? How do I separate parent/child entities of the same $scope that are used in different controllers? What is the better way to substitute View and Edit templates for data being edited by user? Etc...
Or better, is there a sample for the task like mine?
Thanks

I avoid nesting controllers (making controllers depends on scope of their parent controllers), and instead make custom services through which controllers communicate.
Routing of controllers was the biggest issue for me. I've initially started by using ngInclude and handling routing manually, because AngularJS doesn't allow multiple ngViews. Solution was Angular UI Router. They have a simple example that can give you an idea on how to structure your navigation.
Basic principle is:
Any view can have sub view (and it's controller therefore contains sub-controller)
Controllers in hierarchy don't communicate directly through their $scopes. Rather they should use services or events ($scope.$emit, $scope.$on)
Any level of depth can be routed to (e.g. http://myforum.com/#/help-category/how-do-i/msg1)
Take my view with a grain of salt because I'm fairly new to Angular.
Since you're interested in scope inheritance here's an example, but this is discouraged for communication between controllers.
When a controller has a parent controller, then it's scope has a parent scope:
Parent controller:
$scope.Breakfast = 'eggs';
alert($scope.Breakfast); // Shows eggs
Child controller:
alert($scope.Breakfast); // Shows eggs, inherited value
$scope.Breakfast = 'muesli';
alert($scope.Breakfast); // Shows muesli, new value
Parent controller:
alert($scope.Breakfast); // Shows eggs, value remained same
$scope.Breakfast = 'burek'; // Child doesn't see this change anymore
You can get better description and illustrations in Angulars developer guide.

One quick note: don't forget that angular is all about your custom directives, so ideally your html for topic template should look like this:
<div ng-controller="TopicCtrl">
<comment ng-repeat="comment in topic.comments"></comment>
</div>
Angular really allows to write code unbeliavably DRY, so don't be afraid of directives, they will help you with achitecturing your application structure very much.

Related

Initialize the server data from ng-init directive via calling angular controller function?

We have developed one Enterprise application, The complete client side framework is built on AngularJS and the server side framework is on ASP.NET Web API. In the application we have 350+ html pages and 250+ Web APIs. There are lots of areas where we initialize the server data from ng-init directive via calling controller function. Because in our application all data is coming from the ASP.NET Web APIs. But I was surpised upon the documentation for ng-init, which says, in a nice bold outline :
The only appropriate use of ngInit for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
I would like to get feedback from Industry Experts/ Angularjs Core Team Members on my concerns.
Let me brief first what we are doing in the application, for showing a industries list we load the industry HTML page and show the server data. The HTML template code is shown below:
<div ng-init="initIndustries()">....</div>
The "initIndustries" function will be called from initialized industryCtrl. industryCtrl.js code is shown below :
app.controller("industryCtrl",["$scope",function($scope){
//Sets the server data in the $scope property.
$scope.initIndustries = function(){
//perform ajax request and set the data into the $scope property.
}
$scope.initAddIndustry = function(){
// perform ajax request for getting a dropdown data on Add Industry Page.
}
}])
I have few concerns based on Angularjs Doc and Anglarjs-styleguide guideline on Keep Controller Focused which is mentioned below :
Are we doing something wrong to initialize the data via function because all data is coming from the Server APIs?
Current initialization approach is against the industry practices in AngularJS based application. if yes, then which approach we need to follow in the application?
Do we need to create sperate controller for every view just for the shake of client side test coverage, as per the angularjs-styleguide?
The reason to implement the above approach(initialize the data from ng-init directive via controller function), Due to large application my initial thought was to follow MVC philosophy of decoupling the code and separation of concerns.
Angular is known to be Model-View-Whatever. So, it totally depends on you whether you follow a structure in the angular application or not.
Not following a structure has some pros and cons.
Pros
1. A data that is available in one controller can be shared across many views so you won't have to use $rootScope or HTML5 localStorage/sessionStorage to pass data from one controller to another.
Cons
1. As data in controllers is available in multiple views so it is very difficult to maintain the data because the data is obviously bound to views and there will be many implicit angular watches on the same data. That will give bad performance.
Now answering your point 1 and 2 of using ng-init to intialize data in controller. I don't think that will be a good approach because you have made the initialization dependent on the view.
Lets take a scenario in which your view is not found on request and then the initialization won't occur. And as initialization won't occur, there will be garbage values / bugs in controller. So its better to separate the controller initialization from view.
Answer to point 3 is that when you are using a separate controller for every view, you are actually avoiding monolithic code approach and that is always a good point because that leads to modular approach. Separation of concerns in Angular JS is not just done using separate controller for every view but services and directives are also for this purpose in the long run.
Hope that helps you in some way.

Angular Project Architecture

I am building an app in angular, which consumes different APIs and Gives options for the user to select it will be recorded and sent back to the server.
I have designed it as follows.
All the common logic in Main Controller and all other options in different controllers as the child of main controller.
Main Controller retrieve all the data that are required to run the app.
which is consumed by all other child controllers.
To make sure data is loaded I am using promise attached to scope. So all the child controller will know data loaded.
I have moved data updation part of all child controllers to main controller
because all the updates happen in one object.
Child Controller emit/broadcast to communicate between child and main. So when update happens child will emit an event with data which will be captured by Main and it will do the update.
MainController {
$scope.loaded = DataService.get();
$scope.userOptions = {};
$scope.$on('update',function(){
updateUserOptions();
})
}
ChildController {
$scope.loaded.then(function(){
//all logic of child controller
}
$scope.onselect = function(){
$scope.$emit('update',data);
}
}
Questions
Is it a good practice to use events between controllers ?
is it good to use promise attached to scope for child controllers ?
Will it improve my code if I start using services ?
I will try to answer your question based on my own experience. Recently I've built a single page application and I've refactored its architecture.
Here are my answers:
Is it a good practice to use events between controllers? IMHO, it is the most flexible way to share information between all controllers even if they have isolated scope (using $broadcast or $emit for example). This is called the Observer design pattern. However, you can use services instead of events to share data between them. If you are going to use $rootScope, be careful as all the $scopes inherit from $rootScope.
is it good to use promise attached to scope for child controllers ? Firstly, you have to learn about how scope inheritance works. You have to take care to avoid property shadow in JS. Secondly, I would move out all the logic from scope.loaded in ChildController to a service such as ChildService. Keeping the business logic (such as request, etc) in Services instead of Controllers, will ensure it can be re-used.
Segregation of business logic is good design principle.
Will it improve my code if I start using services ? I answered this question above.
In addition, in order to build a good architecture I've read this angular style guide written by John Papa.
I recommend the following changes:
To make sure data is loaded I am using promise attached to scope. So all the child controller will know data loaded.. Instead I would emit a custom 'loaded' event in the MainController using $scope.$emit('loaded'). After that, in the ChildController I would use $scope.$on('loaded', function(){}) to handle the event.
I would move the updateUserOptions function to a service and inject the it into just the controllers that need it.
I hope that helps!
Is it a good practice to use events between controllers ? Not as the main form of data sharing, but you can use it to notify about system events, such as data ready.
Is it good to use promise attached to scope for child controllers ? Don't use scope inheritance, it causes lots of annoying problems.
Will it improve my code if I start using services ? Yep.
This is what I would do in your place:
dataService - this service is responsible for all data coming in / going out. Whenever a request for data is made (no matter which controller asked for the data), the service caches the data (save the promise is good enough). All further requests get the cached data unless they specify they want a fresh data. Whenever data is updated (1st time or refresh), the service broadcasts a 'dataReady' event via $rootScope to which the main controller and other subscribers can listen.
The service is also responsible for data updates, and when the data is updated you can also broadcast an event via the $rootScope.
When the event is activated, all subscribers query the service, and get the data they need.
Controllers - avoid controllers, use directives with isolated scope, and pass the data between them using attributes. In this way you can be sure that each directive gets what it needs, and not everything. The directives can communicate using attributes, services, broadcast / emit or require their parents / siblings if they work closely together.
Is it a good practice to use events between controllers ?
No it's not, it will be deprecated by Angular JS 2.0. It also often leads to unmanagable tangle of events which are hard to understand and debug. Use services to share data between controllers. (Inject same service into multiple controllers, service then holds data, controllers bind to that data and are automatically synchronized) I wrote a blog post explaining this use case.
Is it good to use promise attached to scope for child controllers ?
No it's not. Use promises and resolve data in services. Don't use $scope at all but use controllerAs syntax instead. $scope was deprecated also in Angular JS 1.X because it's usage leads to many different problems with scope inheritance.
Will it improve my code if I start using services ?
YES! Use services for all logic and data manipulation. Use controllers only for UI interaction and delegate everything to services. Also use ui-router for managing state of your application.
I'm not going to answer your questions directly as I have some other comments as well. I think the approach you mentioned is not the best way to build angular applications.
All the common logic in Main Controller and all other options in different controllers as the child of main controller.
It's against all angular style guides to place common logic in controllers. Controllers should only be used for the logic related to the view (data binding, validation, ...). Because the code inside a controller is not reusable, the less code you have in a controller the better. The more logic you have in services, the more scalable your application becomes.
Fix: I suggest you create a service that retrieves data from the server, and inject this service in controllers as you need. Notice also this way offers better dependency management as you can keep track of which controllers need which services exactly.
Nested controllers should be avoided when possible, because angular keeps track of all the active scopes and re-evaluates them in every $apply() loop.
Fix: same as #1, use services instead of the main controller.
To make sure data is loaded I am using promise attached to scope. So all the child controller will know data loaded.
Using a promise for data retrieval is a good practice. But, again, keeping it in a service is much cleaner than main controller.
I have moved data updation part of all child controllers to main controller because all the updates happen in one object.
Child Controller emit/broadcast to communicate between child and main. So when update happens child will emit an event with data which will be captured by Main and it will do the update.
Fix: use a service with an update function instead of events. Events are harder to debug and track. And you need to unregister event handlers on destroying a controller. If you can use a function/promise instead of events, then it's usually a better idea.
Is it a good practice to use events between controllers ?
A problem with your current set-up is that you're implicitly relying on the hierarchy of your controllers (the fact that one is the child of the other) - because you emit the event, only scopes higher up on the hierarchy can catch it. Besides being an implicit connection (that a developer has to remember), this also limits he extendability of this feature.
On the other hand, if you injected a shared service into all the controllers that need it, the connection between the controllers would become explicit and documented, and their scopes' position in the hierarchy independent. This will make your architecture easier to maintain, with the added benefit of also being easier to test, for one.
You can still implement an observer pattern with a service.
is it good to use promise attached to scope for child controllers ?
The issue of polluting scopes pointed out in other answers is valid. This is one of the reasons why it's better to limit the number of objects you attach to your scope, and to use objects as bundles of variables on your scope instead of attaching all the variables to the scope directly.
(For an explanation of these reasons, see discussions about "always having a . in your bindings".)
(Of course, don't do this blindly just to reduce the number of variables, try to find semantic connections between variables that might be bundled together sensefully.)
Will it improve my code if I start using services ?
I think the above answers already outline the answer for this: yes. There are other benefits too, but this format is not best for too long answers, so I won't list anything else now.
All in all, these above pointers are not big issues with your code currently, but if you're looking for the best architecture, I think you can do better.
Answers:
No, it will be deprecated soon.
$scope is deprecated already.
Services is a great choice. Services allow us to share data and behaviour across other objects like controllers.

Angular.js: templates and handling data between views

I'm trying to grasp the main principles related to the next issues:
Templates
Data Handling
$resource vs $http
As i see it i'd like to implement few views in my app which share few html templates and also share some data. for simplifying my issue i'll describe a scenario which is almost equivalent.
as u can see there are 2 views (though there will be more!) who use 3 html markups while one of them is shared in both views (GeneralInfo). Also, both views share data which will be normally created while using one of the view's controller.
What principle of angular should be used to make sure that while changing the route i could keep my data shared between the views.
Should i use app.value('myVal', ..) which is Global variable?
Should i pass it like a service to all of my controllers?
More technically, how should i implement same html in both views? could u example that?
How should a view with it's markup contain 2 templates and how and when it is rendered?
what's the difference between $resource and $http and when each shouold be used?
1) should use a Service to share data between controllers. technically, you could attach values on $rootScope and it would be visible across controllers, but that is considered bad form and can cause problems later (like using global variables -- can definitely have unintended side effects as the project grows if someone accidentally attaches a conflicting value).
2) not sure exactly what you're asking here. you can load a partial based on the given route/state (using ngRoute or ui-router). two different routes could use the same generalInfo.html partial, but with different data being pulled in their respective controllers. is that what you're asking?
3) $resource is an abstraction of $http -- if you're pulling data from a REST server, $resource may be a better fit, as it abstracts a little of the wiring necessary. however, if the server varies from traditional REST principles too much, or if it's not REST at all, you may just want to roll your own data access directly with $http. Of course, if it's REST and more complex, also consider restangular -- which is a more feature rich abstraction.

AngularJS: taking full advantage of AngularJS features/structures

I am working on a web app with AngularJS which I just started learning a while back. I find it extremely useful but after working on it for few days, I figured that the app is going to get all messed up sooner or later, since I wrote all my 'backend' code in one controller.
The app uses lots of $http requests to get/post/delete/put data from/to remote servers and also many scope variables which are needed to manipulate page in one way or another.
I checked lots of tutorials/info sites on AngularJS (similar question, great blog post for instance) but I am still not sure how to implement one of my own within my app. I was wondering what is the usual case with using your own service/module/directive/factory? I am hoping to restructure my code a little bit so everything is going to seem more organized; at the moment I think I am not fully taking advantage of AngularJS with all my code in one place and without using any services/modules besides my main app module and controller and built-in $http.
So you can better understand my problem, so far I only use two javascript files, first one being app.js :
var app = angular.module('MyAppName',[]);
and the second one being controller.js (I could of course use only 1 file for this):
app.controller("MyController", function($scope, $http){
// all my functions/variables in here
// I initialize them with $scope.someName = … if they are needed within this controller view.
// If they are not needed within view I initialize them (functions for instance)
// as functionName = function(){};
}
Everything works as it should this way, but I think this approach is not using all the capabilities of AngularJS. For instance: I don's use routing which I probably should?(url stays the same all the time). I also don't use any other advanced features of angularJS such as custom services/directives/modules.
So I ask: how can I restructure my code so that it uses more of AngularJS features and so that it stays readable? When do you usually create your own service/module/factory ?
I kind of didn't grasp the whole thing on AngularJS site, probably because I started developing too early with not enough knowledge and now I hardly get it (was too much into two-way-binding and started coding immediately).
Any help on the subject is appreciated.
EDIT:
OK, I see I should clear some things up: my main problem is not the outside folder/file structure, but the code structure itself. Now I have one controller which contains every variable (30+) and function to use in my web app, such as login function, sign out function, functions for showing/hiding parts of page, function to add/delete data to/from server etc…
I would like to be able to structure these functions/variables as some independent parts somehow, but I am not sure how.
EDIT2:
I figured how to use services for instance, but unfortunately you cannot call service functions inside views, such as with ng-click directly... you can only call $scope variables which is logical actually... unfortunately i still don't know how to organize my code to seem more readable and structured
There are lots of opinions about how to organize AngularJS code. Have a look at these blog posts:
Code Organization in Large AngularJS and JavaScript Applications
Code Organization in Angular
There are also lots of sample projects out there that showcase various code organization schemes.
Take a look at the angular-seed project:
https://github.com/angular/angular-seed
One alternative to the above is angular-enterprise-seed:
https://github.com/robertjchristian/angular-enterprise-seed
You didn't mention what backend you're using, but there are also similar "seed" projects demonstrating the recommended code organization scheme for AngularJS + [your backend]. For instance, if you're using Express.js, you might want to take a look at angular-express-seed:
https://github.com/btford/angular-express-seed
Data Binding - Angular JS provides two way binding is automatic synchronization of the data between model and view.
Extensible - AngularJS is customized and extensible . Allows you to create customizable components.
Code Reusability and Maintainability - AngularJS forces you to write code in modular way. Variables and functions can only be created to the respective component(Controller). Provides service and factory implemetation to use across the controllers.
Compatibility - AngularJS is compatible to all major browsers
Testing - AngularJS is designed to be testable so that you can test your AngularJS app components as easy as possible. It has dependency injection at its core, which makes it easy to test.
http://astutejs.blogspot.in/2015/06/advantages-of-angular-js.html

Where should I use templating, and where should I generate view objects programmatically?

I am using Backbone.js for an applciation involving a lot of different views, some nesting other views, and these other views could further nest other views.
Also view presentation depends on certain attributes in the model, for instance, some content is only shown if the user has been authenticated, or another type of an if-check
Coming from the world of Adobe Flex, I am used to declaring my views almost completely using markup, even deeply nested, or composite ones. Flex makes component declaration in markup a piece of cake.
I was kinda hoping that I could achieve the same kind of separation between the pure view presentation and the view logic in Backbone, but so far I've been struggling with that.
The reason for this is that in no way can I manage to declare a composite view using templates only. Thus, I have to resort to using BB's render() method to instantiate subviews and append them to the parent. This is OK ... but if the views get really granular, declaring them using JS is an overkill, because I literally end up appending pure HTML strings, which is a complete mess. This means that it is much better to use templating for those ones, and then just render the template instead of doing all the stuff using JS.
Using both approaches simply breaks any consistency in the application, but I push myself to be OK with it, because I've read a lot of (even professionally written) Backbone code, and I 've seen other people struggling with the same thing.
If I cannot avoid this separation of rendering approaches, then at least I will have to put any certain boundaries of which views should be rendered with a template, and which not, or just partially. The question is what will those criteria be.
My methodology is to have all markup contained in templates.
My conception of Backbone Views is that they are actually Controllers. If you consider a Controller in a more traditional web app framework, their job is to receive events, marshal models, fetch and render templates, passing in models, and to return the resulting output.
In Backbone, the Views are the elements responsible for this task. But, instead of http being in input/output medium, the DOM is the input/output medium.
So, I consider Views to be controllers for a specific area of UI on the screen. They listen for events, marshal models, fetch and render templates, and modify the DOM as a result.
The decision of when to go to the trouble of generating a sub-view vs. perhaps rendering a template in a loop, is fairly loose for me.
If it has the possibility of being used in multiple views, I'll make a View out of it.
If it has any events or user interactions which affect itself, but not really anything in the "parent" object I'll make a view out of it.
If it has any real logic, I'll make a view out of it.
If its a related model, or collection, I'll make a view out of it.
But, in any of these cases, the view does not directly generate HTML - I'll always store the markup in a template.

Categories