Framework technical details
must
This document details angular-based mechanisms and key technologies.
Directory: -Routing Mechanism-splitting page modules through routing-lazyload mechanism-command-program Bootstrap-Data Binding-Filters-when to write custom commands-communication between controllers-dependency injection-unified HTTP request interceptor-based on different pages, show different headers menu selection-how to internationalize-how to perform Form validation-animation-test
Routing Mechanism
The routing mechanism refers to how pages are redirected Based on URLs. For example, access#/home
Which page template is to be loaded, and which controller is used to control the page template.
In the spa, routes are controlled by the front-end, and the whole project has only one real page. For example, we only have an index.html page or an index. jsp page.
<body ng-controller="CtrlApp" class="{{lang}}"> <div class="wrap"> <div ui-view="header" class="app-header"></div> <div ui-view="body" class="app-body"></div> </div> <div ui-view="footer"></div> </body>
In our project, the frontend routing is controlled by the UI-router component. The routing controlled by UI-router is actually a state machine that can jump from one status to another. Each status has URL ing and views ing.
// Home $stateProvider.state(‘home‘, { url: ‘/home‘, views: { ‘body‘: { templateUrl: baseUrl + ‘home/home.tpl.html‘, }, header: headerConfig, footer: footerConfig } });
, We define a status home with the corresponding URL/home. The loaded views include body, header, and footer. By referring to index.html, we can know that the home. TPL template will append
And footer. That is to say, when we move to the home status, we get a page like this.
<body> <div class="wrap"> <div ui-view="header" class="app-header"> <!-- header content --> </div> <div ui-view="body" class="app-body"> <!-- home content --> </div> </div> <div ui-view="footer"> <!-- footer content --> </div> </body>
If you need controller to control the page, you can add the Controller dependency in the status, as shown below:
// Home $stateProvider.state(‘home‘, { url: ‘/home‘, views: { ‘body‘: { templateUrl: baseUrl + ‘home/home.tpl.html‘, controller: ‘CtrlHome‘, resolve: { ctrl: $couchPotatoProvider.resolveDependencies([‘home/CtrlHome‘]) } }, header: headerConfig, footer: footerConfig } });
Why addcontroller: ‘CtrlHome‘
Add$couchPotatoProvider.resolveDependencies([‘home/CtrlHome‘])
For more information, seeLazyload Mechanism
.
Use routing to split the page Module
Sometimes the page is complicated and we want to split the page. Consider the following page Structure
You can see that this page looks simple, but it actually contains a lot of content: headers, carousel, digital statistics, recommendation ideas, and the most popular ideas. There is a lot of content, but there is no relevance. Well, we don't want a mess, so we make a change. We hope to split each piece of template and business logic. Here we use routing to help us do this. Check the following code:
// Home $stateProvider.state(‘home‘, { url: ‘/home‘, abstract: true, views: { body: { templateUrl: baseUrl + ‘home/home.tpl.html‘, controller: ‘CtrlHome‘, resolve: { ctrl: $couchPotatoProvider.resolveDependencies([‘home/CtrlHome‘]) } }, header: headerConfig, footer: footerConfig } }) .state(‘home.facade‘, { url: ‘‘, views: { ‘homeBanner‘: { templateUrl: baseUrl + ‘home/banner/homeBanner.tpl.html‘, controller: ‘CtrlHomeBanner‘, resolve: { ctrl: $couchPotatoProvider.resolveDependencies([‘home/banner/CtrlHomeBanner‘]) } }, ‘homeCount‘: { templateUrl: baseUrl + ‘home/count/homeCount.tpl.html‘, controller: ‘CtrlHomeCount‘, resolve: { ctrl: $couchPotatoProvider.resolveDependencies([‘home/count/CtrlHomeCount‘]) } } });
We can see that the state home is defined as an abstract state.abstract
And define the sub-State of a home as home. facade. The URL is '', so that accessing a URL such as #/home triggers the home route and home. Facade route. Note that the home. Facade route defineshomeBanner
AndhomeCount
Defined in home.tpl.html
<div> <div ui-view="homeBanner"></div> <div ui-view="homeCount"></div> </div>
In this way, the page can be split into sub-modules. If you need to introduce these modules on other pages, you only need to define them in the routing, and then declare the required UI-view in the parent template to reuse them.
Lazyload Mechanism
The lazyload mechanism allows you to load resources required for the page as needed when the status is transferred, instead of loading resources at the beginning. Angularjs itself does not implement lazyload. In this way, the performance of the webapp is affected. When loading for the first time, all dependencies must be loaded.
// Define angular module var APP = Angular. module ('app', ['scs. couch-Potato ', 'ui. router ', 'ui. bootstrap ', 'ui. bootstrap. tpls ', 'chieffancypants. loadingbar ']);
The code snippet above demonstrates the angular module loading mechanism. In practical applications, especially business systems, the services are generally complicated and there are many functional modules. In this case, the default mechanism of angular module does not meet our requirements.
Therefore, we use requirejs + angular-couch-patato to implement lazyload. Angular-couch-patato is responsible for hosting various angular registrations, including controller, Directive, filter, and service. We usually write
angular.module(‘app‘).controller(function () { //ctrl code here });
To use lazyload, We need to write
angular.module(‘app‘).registerController(function () { //ctrl code here });
Register the parts so that all parts are handed over to couch-patato for management. When necessary (how to use it is described below ). With the use of requirejs, the app is a centrally managed angular module, which is written as follows:
define([‘app‘], function(app) { app.registerController(function () { //ctrl code here }); })
Load the dependent app first. The app is the angular module defined previously, as shown in figurevar app = angular.module(‘app‘, [‘scs.couch-potato‘, ‘ui.router‘, ‘ui.bootstrap‘, ‘ui.bootstrap.tpls‘, ‘chieffancypants.loadingBar‘]);
. Then register the Controller on the app.
AboveRouting Mechanism
Some mentioned that when registering a route, you need to call $ couchpotatoprovider. resolvedependencies to implement lazyload. Here, the key to couchpatato implementation is to use angular's resolve mechanism in the routing. Here, resolve means that the routing must get all the values defined in resolve before being triggered. In this way, couchpatato has the opportunity to obtain the defined dependencies. In each dependency, the controller is registered to the app, and then the defined controller is called after the routing is triggered.
Command
Directive. A major feature of angular, which can define a tag or give Dom some function, is also the only place in angular program to operate the Dom. Multiple Use of one definition is a powerful tool for componentization!
How to define commands?javascript app.registerDirective(‘dragable‘, function() { return { link: function(scope, element, attrs) { //code make it dragable } } });
The code above defines an instruction that provides the ability to drag.
If you declare in the template that you need this capability, he will have this capability.html <div dragable></div>
You can drag this Div!
That's amazing. When you are still waiting for the HTML5 specification to come out, and you are still waiting for various browser vendors to implement this specification, angular will help you do this, this problem is solved technically.
One of angular's Zen statements is declarative over Imperative! When you declare it, you have it. how nice it is. For more information about direve ve, visit https://docs.angularjs.org/guide/directive.
Commonly used angular built-in commands-ng-repeat iteration-ng-if control display-ng-model data model binding
Program Bootstrap
How does angular parse commands and obtain control? (Because there are other portals, I believe many backend players do not have this concept, and they never need to care about the main function. But the Web is different. The web loads HTML first, loads JS after rendering, and then the JS can host the entire app)
Angular Bootstrap can be manually initialized or automatically initialized.
The automatic initialization method defines the NG-app Directive in the HTML Tag. After angular. JS is loaded, the entire HTML will be compile and the DOM of the NG-app will be used as the root to generate dynamic HTML. HTML <HTML ng-app>
</Html>
Manual Initializationjavascript angular.element(document).ready(function() { angular.bootstrap(document, [‘myApp‘]); });
We chose to manually initialize angular in Main. JS, so that we can do more things, such as loading things we need during initialization, such as permissions and users.
Data Binding
In angular, data binding is bidirectional binding. Bidirectional binding means that the corresponding data changes when the view changes, and vice versa. Data Binding is available in many MVC frameworks, but data binding in angular is a useful method. Let's take a look at what we need to write:
<div ng-controller="Ctrl">{{name}}</div>
Function CTRL ($ scope) {$ scope. Name = 'fried strike ';}
Once the data name changes, it is directly reflected in the view. All the intermediate processes are handled by angular.
Filters
Filter is used to display the data in format.
<div class="date">{{date | dateFilter}}</div>
Datefilter is the date filter, so the data source does not need to be changed. We only consider how to display it. The following is a custom filter statement.
app.registerFilter(‘PortionFilter‘, function () { return function ( input ) { if ( input <= 1 ) { return ( input * 100 ).toFixed( 2 ) + ‘%‘; } return input; }; });
When to write custom commands
- Commands can be understood as componentized. When multiple scenarios require the same functions, you should write one command.
- When you have to perform Dom operations, write commands
- When you need to extend the DOM function, write the command
- If the open-source community has better commands with the same functions, you can use them or refer to them.
Communication between controllers
Sometimes, CTRL communication is required. We perform different processing based on different CTRL relationships. When CTRL has a parent-child relationship or ancestor relationship, we use $ broadcast and $ Emit for communication. $ Broadcast spread down, and $ emit is vice versa. When there is no direct hierarchical relationship, we use their common parent-level CTRL for interaction, because no matter how CTRL is distributed, they eventually have a common root. The specific method is to define a variable they jointly maintain at the parent level Ctrl, then listen to the change of this variable, and finally communicate through $ broadcast, $ emit. The Parent-level CTRL is equivalent to a man-in-the-middle.
Use.
For communication https://egghead.io/lessons/angularjs-the-dot
Dependency Injection
Angular is one of the best features. Dependency injection is a manifestation that declarative statements are better than imperative statements. See the following code:
function Ctrl($scope, $http) { $scope.doSth(); $http.doSth();}
We can see that when we want to use the $ HTTP service, we only need to declare it to obtain the reference. Compiling angular services is very simple.
app.registerService(‘util‘, function(){ return { compress: function A(), sthElse: function(){ console.log(1); } }; });
With this capability, we can streamline the code in ctrl and extract reusable or lengthy business code so that CTRL can focus more on business processes, the specific service code is maintained in the service.
Unified HTTP request interceptor
Angular allows you to register an HTTP request interceptor. What's the purpose? Yes. It is useful when you want to uniformly process certain types of requests. If you want the backend to return 404, you can jump to the 404 page. In this way, you do not need to add this section to the processing function of each HTTP request. You can also perform anti-Cache processing and judgment on IE. If it is an earlier version of IE browser, a timestamp is added to each GET request. Nice!
Play ground: YouTube top loading effect!
Different headers are displayed on different pages.
For example, on the home page, the homepage is hit. When it comes to the List page, the header should hit the list. How to implement it? 1. you must define a set of hit rules in the corresponding controller. The rule specifies which route should be highlighted and which item 2. define a Service to manage the selected header, and call the service in each route-level controller to change the highlighted
How to internationalize
What is internationalization? internationalization displays different texts based on different languages. The idea is to load different resource files according to different languages. For example, when it is Chinese we use zh-cn.json, English when we use us-en.json.
In angular, the filter is used for display. So let's make a fuss about the filter. For static text, we use a key instead of a 'linguistic '. We use 'lang' to replace it. In HTML, we write {'lang '| translate }}, the filter function of translate is to find the text corresponding to the 'lang 'key from the Language Pack we loaded earlier.
{"Lang": "Chinese "}
So what should we do with dynamic data? This requires some agreement with the backend. -For the value list, we directly translate the i18n data-Enumeration type, and specify to return meaningful strings, such as 'success 'and 'failed '. Then we make some stitching at the front end, such as {'Type'+ Type | translate}, and then we add the type to the resource file.The keys of success and type_failed are OK ~ -Here we encourage rd to return meaningful strings instead of 0, 1, and 2.
In addition, internationalization not only affects text, but also may affect layout. That is to say, different language environments and different page sizes. In this case, our processing is similar to skin-changing, we bind a class in the language environment to the body, and perform different processing based on special requirements.
If internationalization affects the business logic, we recommend that you perform logical judgment on the language environment of the module.
How to perform Form Verification
Form Verification is a difficult problem for centuries. Students may have used various jquery Form Verification plug-ins. Isn't it easy to use ..
Why is form verification difficult? It is because you not only need verification, but also need different verification methods. Therefore, it is often handled according to the specific situation. The following describes a common verification processing method.
<div class="material-url form-group"> <label class="control-label col-md-2"> url: </label> <div ng-class="{‘has-error‘:e.materialValidator && formAd.materialUrl.$error.required}"> <div class="col-md-3"> <input placeholder="" type="url" class="form-control" name="materialUrl" ng-model="e.adSolutionContent.materialUrl" /> </div> <div class="col-md-3 help-block" ng-show="formAd.materialUrl.$error.url"> {{‘AD_CONTENT_NO_URL‘ | translate}} </div> </div> </div>
Enter a valid URL for input. If the URL is invalid, an error message is immediately displayed on the right. This angular is very easy to do... Then we can invalidate the submit button.
<button ng-show="form.$valid" />
But the abnormal demand comes again, and the button can always be clicked... Well, let's make a judgment when submitting the statement. We also use form. $ valid to easily determine whether the form is OK. If it is OK, it is OK. Otherwise, we need to focus on the input with the first error. Then we can only sadly judge whether the input is legal, and then write a command to control the focus action.
In summary, form verification is performed based on different requirements.
Animation
Angular recommends using css3 for animation processing, because angular can easily manipulate data, so that CSS can be easily switched and then moved through css3. Https://docs.angularjs.org/guide/animations, through angular tutorials can build a simple list animation.
Test
Angular programs can perform tests, which is amazing because angular limits all Dom operation code to commands, and Dom operation code is difficult to test. As mentioned above, we try to encapsulate the logic processing code into the service so that we can test the service and ensure the quality of the Code.
Angular tests are also effective against dependency injection, because this is the key to running tests. The test routine will first create an angular-Mock, fake shell, and then use the $ Injector in it. get () to load the service you want to test. Now you can get the instance of the service. Angular recommends Jasmine.
Angular usage Overview