I am working on a project targeting mainly mobile devices.
The app receives a list of different objects from the server which shall be rendered all at once.
Each object type has it's own directive, which takes care of business logic. But because most objects share certain features we created 'sub-directives' which work as mixins to keep it DRY.
If more than just a handful of those objects should be displayed (which is the default case), Angular takes quite some time parsing and instantiating those directives + sub-directives.
Our performance improvements so far:
replaced the ng-repeat with a custom directive, which also works like an infinite-scroll
use bindonce to limit bindings only where they are really necessary
pre-fill the $templateCache with the templates, instead of fetching
them via templateUrl
But even with those improvements, the performance is still not acceptable. (Especially when navigating to the state containing the list)
The approach I have in mind now is as follows:
let Angular fully parse and create one such directive with its
sub-directives
cache the resulting node
if we have another object of the same type simple reuse it and link it with a new Scope
But even after going through Angulars source code I have no clue where I could hook in to receive the finished result before advancing to the next object in the list.
So far it parses the template of the actual directive for each entry in the list, then comes back and finishes the sub-directives.
Hope I was able to make it understandable what I am trying to accomplish.
Thanks in advance!
Related
My app seems to have views with a lot of logic in them. My question is two fold:
Does logic in the view slow down angular app performance?
As a best practice, is it better to treat this logic in the controller and just store the outcome in a $scope attribute which the view can access ?
Would this improve performance ?
Example of views in our app (a simple one):
<div class="small-12 column" id="notificationMsg">
{{ config.message | translate : config.getMessageParams(notification)}}
</div>
short answer:
yes
long answer:
your bindings will have to be updated in every digest cycle which affects the used variables.
storing the value in a variable and only updating it if something changes will improve your performance.
however this will only be critical if you reach a certain amount of complexity. as long as your app doesn't grow too much this won't be a threat to think about - yet.
i wouldn't necessarily call it a best practice, because it can make your code more complex and harder to read/understand/maintain.
performance isn't always an issue. it just starts to be one as soon as it's absent by default ;)
a further improvement you can do is use ng-bind and ng-bind html instead whenever possible, because it can be rendered faster, since it can skip some internal steps of angularJS whilst compiling the expression.
so e.g. use
<div ng-bind="foo"></div>
instead of
<div>{{ foo }}</div>
if possible
The key concept behind these performance considerations is reducing the number of $$watchers inside Angular to improve the $digest cycle’s performance, something you’ll see and hear more of as you continue working with Angular. These are crucial to keeping our application state fast and responsive for the user. Each time a Model is updated, either through user input in the View, or via service input to the Controller, Angular runs something called a $digest cycle.
This cycle is an internal execution loop that runs through your entire application’s bindings and checks if any values have changed. If values have changed, Angular will also update any values in the Model to return to a clear internal state. When we create data-bindings with AngularJS, we’re creating more $$watchers and $scope Objects, which in turn will take longer to process on each $digest. As we scale our applications, we need to be mindful of how many scopes and bindings we create, as these all add up quickly - each one being checked per $digest loop.
Angular runs every single filter twice per $digest cycle once something has changed. This is some pretty heavy lifting. The first run is from the $$watchers detecting any changes, the second run is to see if there are further changes that need updated values.
Here’s an example of a DOM filter, these are the slowest type of filter, preprocessing our data would be much faster. If you can, avoid the inline filter syntax.
{{ filter_expression | filter : expression : comparator }}
Angular includes a $filter provider, which you can use to run filters in your JavaScript before parsing into the DOM. This will preprocess our data before sending it to the View, which avoids the step of parsing the DOM and understanding the inline filter syntax.
$filter('filter')(array, expression, comparator);
Yes, for better performance, Use
$scope.description: $translate.instant('DESCRIPTION')
in Controller, instead of,
{{'DESCRIPTION' | translate }}
Furthermore,
It depends on what you want to achieve. Here is another way to increase performance.
One Time Binding
Angular 1.3 added :: notation to allow one time binding. In summary, Angular will wait for a value to stabilize after it’s first series of digest cycles, and will use that value to render the DOM element. After that, Angular will remove the watcher forgetting about that binding.
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.
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
I have an app I am designing using node/mongo/angular, what I am not getting is how is the best way to get my data from mongo into my pages? I can use node, and thru my routes send back data from mongo with my template(hogan in this case), and bind using mustachejs. That works fine for most things. I have one screen that has a decent amount of drop down lists, to bind them for an edit scenario now seems a challenge. I would like to get them bound to an angular model and go about it that way. Is it better to get the data thru the route in node, then use something like ng-init and get it into angular? Or would I be better off not getting the data thru the route in node, and then using angular to perform a "get" request and bind that way?
From the documentation of ng-init, more precisely from the red warning alert at the top of the page...:
The only appropriate use of ngInit is 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.
So no, do not use ng-init. While that can be a good strategy for lazy migrations from regular applications to single page applications, it's a bad idea from an architectural point of view.
Most importantly, you lose two things:
An API. The benefit of SPAs is that you have an API and that you're constantly developing and maintaining it, even before it has external users
A clean separation of concerns. Views are strictly limited to presentation, can be cached by the client and all data is transferred through JSON API endpoints.
I would say that the best way to get data from Mongo into your page, is as mnemosyn said, using an API.
Basicly, you can have your API route, f.ex '/api/data' configured and then it can be used by a angular service, (which can use ngResource to make things easier). Any controller that wishes to access this data can use the angular service to get it, do some stuff with it, and then update it using the same angular service.
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.