How does AngularJS do what it does (what makes it tick) - javascript

I'm looking at AngularJS, trying to learn the basics. Quite experienced with JavaScript and server programming, HTTP etc, so I do have an understanding of what it does. I'm watching Curran Keller's "50 examples" tutorial on YouTube (link below), and I've found lots of documentation on what Angular does... but not so much on how it does it. Knowing the rough on how Angular is able to do all these neat things -- it being "only" a JavaScript wrapper, executing in the web browser -- would be helpful when I am to write my first Angular "app" (webpage with metadata-enhanced JS, as I currently think of it). ;-) that ought to get the discussion going!
So, here's what I think I've gleaned so far:
Angular JS is JavaScript. It runs in the browser, via a .js file, so eventually the directives and tags and "angular code" (controller) is translated into JavaScript, which is what's actually run in the browser.
As such, Angular is really "just" a library of wrappers for normal JavaScript objects. I guess this is the main point; it's a simplification of the otherwise rather complex "native" JavaScript code. For example, rather than instantiating an XMLHttpRequest object, and using it to GET or POST some data to/from a server, Angular provides an $http service. All you need to type is $http.get();
Furthermore, Angular has this powerful dynamic propagation of changes in the UI, as the user uses the page. Almost like in Excel, if a piece of data is changed somewhere, then all other usages/references of same data (i.e. a variable, an HTML form element, or just a variable output to HTML with {{myVariable}}) are updated accordingly. Automatically, and immediately.
Another cool property is enhancing HTML tags with Angular directives. This is a very simple way of dynamically producing HTML output (or just plain text) from what ever is in the Angular (i.e. JavaScript) memory. Again, this can be done with plain vanilla JS, traversing the DOM and inserting child elements, but Angular alleviates the need for any of that complex coding. All you need to program is <li ng-repeat="name in names">{{name}}</li>
So, how does Angular achieve all this, using "only" JavaScript? Obviously, as with GetElementById, JavaScript can access (read) and parse the HTML DOM, so I take it Angular begins by reading in the entire document and looking for any HTML tags with the ng-app directive. These are parsed further, and Angular code is converted to either generate additional HTML output (e.g. ng-repeat), or translated into embedded JavaScript (as in $scope.name='';).
One thing I've had trouble finding an answer to in the documentation, is what the dollar signs do. I think I know the answer, but I'm not confident. Since Angular has its own JavaScript-like programming language, Angular needs to be able to discern between the JavaScript-parts (e.g. variables used in HTML FORM elements) and the Angular objects. I mean, what's Angular function calls and what's the input/arguments to those. Prepending $ to the Angular words lets the Angular JS-translator know what not to translate, so to speak?
Maybe someone can follow up on this, correct me where I'm wrong?
The examples in Curran Keller's "Introduction to Angular.js in 50 Examples" (http://youtu.be/TRrL5j3MIvo) is a great reference. For instance, maybe the dollowing simple example could be a starting point? In this example, I'm wondering (in addition to the above thoughts) what specifically is the purpose of the $scope object. Can we rename it to $whatever, or is "scope" a reserved word?
<html ng-app="nameApp">
<head>
<meta charset="utf-8">
<title>Angular.js Example 14</title>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.min.js"></script>
<script>
var nameApp = angular.module('nameApp', []);
nameApp.controller('NameCtrl', function ($scope) {
$scope.names = ['Larry', 'Curly', 'Moe'];
});
</script>
</head>
<body ng-controller="NameCtrl">
<ul>
<li ng-repeat="name in names">{{name}}</li>
</ul>
</body>
</html>

One thing I've had trouble finding an answer to in the documentation, is what the dollar signs do.
The dollar signs are simply a naming convention reserved for Angular and JQuery. It's simply for readability to quickly discern what is Angular/JQuery functions. See http://google.github.io/styleguide/angularjs-google-style.html#dollarsign.
In this example, I'm wondering (in addition to the above thoughts) what specifically is the purpose of the $scope object. Can we rename it to $whatever, or is "scope" a reserved word?
$scope is special, it refers to the application model. See docs.angularjs.org/guide/scope and docs.angularjs.org/guide/controller (can't post direct links because I don't have the reputation yet :( ).
In the above example, $scope is used to communicate between the controller and the DOM. The DOM can only refer to items on the scope in angular bindings. Breaking down the example above:
<body ng-controller="NameCtrl">
This instantiates the controller named NameCtrl, and sets up the same $scope between the DOM and that instance of NameCtrl. This element and all children elements can now reference the same $scope as NameCtrl.
$scope.names = ['Larry', 'Curly', 'Moe'];
This is where the controller is setting the model to Larry/Curly/Moe for the DOM to consume.
<li ng-repeat="name in names">{{name}}</li>
"names" refers to the same $scope.names in NameCtrl (remember, you don't write $scope from the DOM). Whenever the controller NameCtrl updates $scope.names, the DOM will update as well, creating a list item for each element in the array 'names', and each element has it's own $scope as well.
I suggest going through some of the AngularJS tutorial app helps quite a bit: docs.angularjs.org/tutorial/

Related

Best way to pass server (c# / Razor) values into an AngularJS app

We use DNN and often need to pass a few context specific values (like page id or module-on-page-id) into an AngularJS app. We've developed our own conventions how to do this, but would like to hear from others how they approach this to find a best practice.
So basically the situation is that the server-page has information needed by the JS. Using WebAPI is not an option, as these values are known in the page, but not in a separate request. Things I've seen so far have been:
Use in-view-razor like href="#Tab.TabId/{{...}}" (I don't like this)
Place the values in the ng-init like ng-init="config = { prop1: '#Tab.TabId' }"
Create a separate <script> tag where we generate a module on the fly containing these values so angular.module("config", []).constant('prop1', '#Tab.TabId')
Create a json with razor in the page somewhere and inject all of it as a module into the app using a generic code which does the same as #3, just with cleaner code re-use.
I've seen all these and have also used all. Currently we avoid #1 as we believe it's not good to mix templating languages and because it doesn't allow externalizing parts of the view. So basically we use #2 as for quick-and-simple (and a bit dirty) + #3/#4 for larger projects.
Do you have a better way, or which way would you prefer?
We are using variant #4.
This has the advantage that the JSON defines the exact interface for the config needed by the JS module. And Razor is great to generate URLs using #Url.Action.
we use NewtonSoft and do JSONConvert.SerializeObject(ObjectName) and then pass it over as a Session from the controller and then use #Html.Raw(ObjectName) and its a JSON Object that can be utilized easily in javascript...

Security of Angular expressions

I am going through the PhoneCat tutorial for AngularJS. Everything is explained really well, so i was following along until i hit step 6 in which links are generated dynamically from angular expressions:
http://localhost:8000/app/{{phone.imageUrl}}
While the tutorial states that ngSrc is preventing the browser from making http requests to invalid locations (edit: apparently the tutorial means the browser will only call the link after the expression got evaluated. See the "Experiments" section in the provided link.), i am now wondering of how secure angular-expressions are in general. Since the phone.imageUrl is loaded externally, it theoretically could contain malicious content and i would like to understand why this would not matter to my webapp.
Obviously the content of expressions gets escaped in some way, so including the following in your code will just print out some text:
<img ng-src="{{""><script>alert('UNSAFE!')</script>"}}">
but i would like to know if there are some "rules" that you need to be aware of to keep your webapp secure. Would for instance compiling the above code via
var template = "<img ng-src="{{""><script>alert('UNSAFE!')</script>"}}">";
var something = $compile(template);
result in executing the script when the DOM is loaded? Are there "things" that you should not do in your webapp when you can't ensure that the angular expressions contain the expected content?
As far as I know angular always escapes any data bound to elements unless you tell it not to do so.
Your example on the other hand works differently – maybe you're a little unsure how angular works:
var template = "<img ng-src="{{userInput}}">";
var something = $compile(template)({userInput: "\"><script>alert('UNSAFE!')</script>\""});
So the template, which you have full control of, get's first compiled and then the expression is bound to it completely escaped (no html allowed).
I'd probably not compile external code ($compile(userinput)) without sanitizing it first – but that would mean you may be doing something wrong. If you code the right way, you will use $compile only in some edge cases. Otherwise you may stay calm since angular will take care of unsafe input.
If you need to bind html to template, then you can include ngSanitize. Otherwise angular won't let you bind unsafe html, unless you tell the $sce service to trust it.
In conclusion, I would not worry about binding data from untrusted sources to my template.

Angular.js load, process and display dynamic template obtained via REST $resource

I have an Angular app that needs to support customizable reporting. My intention is to allow the user to select one of many reports available and have a back end REST api provide the template and the data as JSON (end user can customize the template).
The app would then insert the template somehow into a "reporting" view page then put the data in the scope and Angular should compile and display the report / template.
I've looked into ng-include however that seems to support only an URL or path to a document, however I have the template text already via the REST service and I cannot use static urls or file paths, this needs to be via REST api, if ng-include accepted the template text directly that might work but it doesn't.
I've tried writing a directive, trying to call a method on the page (getTemplate()) that would load the template already fetched from the scope however my directive doesn't have access to the scope apparently.
What tactic should I use to accomplish this? A directive seems best but I'm obviously doing it wrong and completely lost in the docs and my many attempts trying to accomplish this.
You could compile the dynamic template to an element on the DOM in a controller and then in the controller have something like this:
var el = angular.element('#myselector');
el.html(mydynamichtmlfromresource);
$compile(el.contents())($scope);
I would setup your route with template with single DIV container (you could pull all the static container template in a single JavaScript file using HTMLToJS online tool or grunt task):
<section class="view">
<div id="myselector"></div>
</section>
I've tried writing a directive, trying to call a method on the page
(getTemplate()) that would load the template already fetched from the
scope however my directive doesn't have access to the scope
apparently.
Yes you are right, but there is a way to pass data from scope to directive. lets say you want to pass a var "x" from scope to directive
use this
<directive directiveVar='x'/>
inside directive, you need to use isolated scope
"scope": {
"directiveVar": "="
},
this variable will be available only in controller and postlink function, so your directive template needs to be like this
<ng-bind-html="directiveVar"/>
inside the postlink you may need to use this code snippet
$scope.directiveVar =$sce.trustAsHtml($scope.directiveVar)
References
http://docs.angularjs.org/api/ng.directive:ngBindHtml
http://docs.angularjs.org/api/ng.$compile

Build html in server and bind to ng-repeat

I have some table that ng-repeat is building. the table contains a lot of data, and sometimes the build phase of the html is taking 10-20 seconds on weak computers.
So i've started to explore about building the html in the server, but the problem is that i'll loose the data-binding, and i'm needing it because i have inline edit functionality in the table.
The ultimate solution will be rendering the table in the server-side, with all the directives remaining including the ng-repeat, and on the client, makes the ng-repeat recognize that the html already has been rendered for the first time and not render it again, until the first change in the data.
In the Angular source code in the ngRepeatDirective, there is the "lastBlockMap" object that contain mapping betwee each element created by ng-repeat, to his scope, in that structure :
clone: [THE_ELEMET]
id: "005"
scope: ChildScope
and from reading this arcticle :
http://www.bennadel.com/blog/2443-Rendering-DOM-Elements-With-ngRepeat-In-AngularJS.htm
i've got to conclusion that if i'll create this object, and pass it somehow to the ng-repaat directive, the directive will know that the html is already been rendered and will not render it again.
The problem is how to pass such information to ng-repeat???
Any one encountered this situation??
P.S.
I'm familiar with all the "ngRepeat preformance" posts and arcticles and have tried a lot of other options before approaching this solution, so please try to help me with this one.
Second P.S.
Sorry for my english... :)
There is no solution for compile the html into loop in angular.
maybe you need to try clean the json data you try to render and make it as simple as you can, and if you include directive inside the table, try to render it after the table is done.
also, try to isolate the reason for the slowness, disable the inline edit and all the other featers inside the table.
Use prerender.io to render the html on the server side. It basically opens a phantomjs process and executes the JS on the server, and serves the output. Works pretty well.

When using (only) a templating system, how should I manage CSS, javascript etc for sub-templates?

I've had this same question when working with different templating systems in different languages in the past, so first,
The general question
I want to use a sub-template to include a certain UI component which might appear in different places on a number of different pages. This UI component requires certain CSS and JS files.
I want to Do The Right Thing with CSS and JS resources, which, as far as I know and in broad terms, is to a) combine as many as possible b) minify as much as possible and maybe c) put what I can at the end of my markup so the browser doesn't have to wait for them to load before displaying content.
So, if I've got various different UI components, as well as different headers and sidebars in different sections of the site, which all require their own special CSS and JS to function correctly, what's the best way for me to manage them through a templating system so that the final markup is as small and well-organised as possible?
Specifics of my situation
I'm working on a large legacy PHP site, on which, to give the original authors the benefit of the doubt, development may have begun before MVC became really mainstream, and before there were so many choices of frameworks around to use. So there is no consistent MVC framework, no routing, no templating (no ORM either, but that particular curse isn't as relevant here).
I'm going to have to keep things ticking over, squashing bugs and adding a few new features until a complete rewrite is usable, so I'm trying to breathe some sanity into things as I go along.
The easiest place to start seemed to be the views layer, for which I'm using TinyButStrong. An example of their sub-templates can be found here, but like I said, I think this is a very general question.
Things I've considered
With a more integrated framework I'd like to be able to do something like $view->add_js($foo), but transitioning to a full-blown framework is what other people are doing while I try keep the existing codebase seaworthy. There isn't even really enough consistent organisation of files to roll something like this by hand.
At the moment the best thing I can come up with is making a DOMDocument out of the view right before it's output and manipulating <link> and <script> tags at that point. I don't know if that's a bit crazy though. Given the generality of the problem I'd like to think that there's a known sensible way to go about it.
Many thanks for your input.
It's hard for the reader to know what can or cannot be done with your code base. A common way to handle this situation would be to pass parameters to the view template, and the template can then include conditional chunks or include sub-templates based on your parameters. This does not require a full-fledged framework, a stand-alone template engine should do. If your template engine supports inheritance there is a nice pattern for handling assets in your templates - check here for example http://symfony.com/doc/2.0/book/templating.html.
Manipulating the Dom for each request to handle this kind of thing seems bit unorthodox.
What you want in this situation is some form of template inheritance; that is, technology whereby a sub-template has access to areas in a 'parent' template, and can edit or replace content in those areas. Using this ability, CSS and JS required for a component included via a sub-template can be added in to the <head> element of the parent page.
In Twig, this is achieved using named blocks. First, you create your parent template (or layout, as it's called in Twig), e.g. index.html.twig. You include in it a named block like {% block myCss %}.
Next, to create a sub-template, you begin the template with the line {% extends ::index.html.twig %}. Then, the content of a block defined in the sub-template with the same name as a block in the parent template (in this case {% block myCSS %}) will get substituted into the parent template. To append rather than replace content in the parent template, use {{ parent() }} to include content already existing in the parent.
An example of this with code is available at the link given by #Basel Shishani. I've heard that Twig is modelled after Django, and template inheritance in Django looks very similar (with the exception of using {{ block.super }} instead of {{ parent() }}. There is a discussion of how to achieve the same ends in TinyButStrong.
As a wider point, the Assetic library looks like a very promising solution for managing CSS and JS assets, in order to avoid duplication (e.g. where the same JS file is required by multiple components/subtemplates), enable concatenation and minification of assets, and more. This presentation of its features gives more details.

Categories

Resources