通过本分类您将了解到:1、AngularJS技术学习资料整理收集;2、博主在世纪项目应用中的经验教训;本分类直接访问网址:http://angularjs.name
Pages: 1/2 First page 1 2 Next page Final page [ View by Articles | List ]
Oct 11
一、service引导

刚开始学习Angular的时候,经常被误解和被初学者问到的组件是 service(), factory(), 和 provide()这几个方法之间的差别。This is where we'll start the twenty-five days of Angular calendar.

二、service

在Angular里面,services作为单例对象在需要到的时候被创建,只有在应用生命周期结束的时候(关闭浏览器)才会被清除。而controllers在不需要的时候就会被销毁了。

这就是为什么使用controllers在应用里面传递数据不可靠的原因,特别是使用routing的时候。Services are designed to be the glue between controllers, the minions of data, the slaves of functionality, the worker-bees of our application(就是说services在应用的controllers、 方法、数据之前起到了很关键的作用)



现在我们开始看怎么创建service。每个方法我们都会看到下面两个一样的参数:

name-我们要定义的service的名字

function-service方法

他们都创建了相同的底层对象类型。实例化后,他们都创建了一个service,这些对象没有什么功能上的差别。

1、factory()

Angular里面创建service最简单的方式是使用factory()方法。


factory()让我们通过返回一个包含service方法和数据的对象来定义一个service。在service方法里面我们可以注入services,比如 $http 和 $q等。


在应用里面使用factory()方法

在应用里面可以很容易地使用factory ,需要到的时候简单地注入就可以了


什么时候使用factory()方法

在service里面当我们仅仅需要的是一个方法和数据的集合且不需要处理复杂的逻辑的时候,factory()是一个非常不错的选择。

注意:需要使用.config()来配置service的时候不能使用factory()方法

2、service()
service()通过构造函数的方式让我们创建service,我们可以使用原型模式替代javaScript原始的对象来定义service。

和factory()方法一样我们也可以在函数的定义里面看到服务的注入


这里的功能和使用factory()方法的方式一样,service()方法会持有构造函数创建的对象。

在应用里面使用service()方法



什么时候适合使用service()方法

service()方法很适合使用在功能控制比较多的service里面

注意:需要使用.config()来配置service的时候不能使用service()方法


3、provider()

provider()是创建service最底层的方式,这也是唯一一个可以使用.config()方法配置创建service的方法

不像上面提到的方法那样,我们在定义的this.$get()方法里面进行依赖注入


在应用里面使用provider()方法

为了给service进行配置,我们可以将provider注入到.config()方法里面


这样我们就可以和其他方式一样在应用里面使用这个service了


什么时候使用provider()方法

当我们希望在应用开始前对service进行配置的时候就需要使用到provider()。比如,我们需要配置services在不同的部署环境里面(开发,演示,生产)使用不同的后端处理的时候就可以使用到了

当我们打算发布开源provider()也是首选创建service的方法,这样就可以使用配置的方式来配置services而不是将配置数据硬编码写到代码里面。

还可以看看这篇翻译:http://www.oschina.net/translate/top-10-mistakes-angularjs-developers-make



点击查看完整的代码:https://gist.github.com/auser/7743235
Oct 11
Highslide JS
AngularJS实现注入服务的方法有5种方式:
decorator
constant
value
service
factory
provider
其中provider是一切方法的基础,有点类似于XMLHttpObject,在这个基础之上建立起来的,像jquery的$.ajax等等。

第一种方式:decorator


第二种方式:constant



第三种方式:value


第四种方式:service



第五种方式:factory



第六种方式:provider
Oct 11
理解AngularJS中的依赖注入
AngularJS中的依赖注入非常的有用,它同时也是我们能够轻松对组件进行测试的关键所在。在本文中我们将会解释AngularJS依赖注入系统是如何运行的。

Provider服务($provide)
$provide服务负责告诉Angular如何创造一个新的可注入的东西:即服务(service)。服务会被叫做provider的东西来定义,你可以使用$provide来创建一个provider。你需要使用$provide中的provider方法来定义一个provider,同时你也可以通过要求改服务被注入到一个应用的config函数中来获得$provide服务。下面是一个例子:

代码laycode - v1.1
在上面的例子中我们为一个服务定义了一个叫做greeting的新provider;我么可以把一个叫做greeting的变量注入到任何可注入的函数中(例如控制器,在后面会讲到)然后Angular就会调用这个provider的$get函数来返回这个服务的一个实例。在上面的例子中,被注入的是一个函数,它接受一个叫做name的参数并且根据这个参数alert一条信息。我们可以像下面这样使用它:

代码laycode - v1.1
现在有趣的事情来了。factory,service以及value全部都是用来定义一个providr的简写,它们提供了一种方式来定义一个provider而无需输入所有的复杂的代码。例如,你可以用下面的代码定义一个和前面完全相同的provider:

代码laycode - v1.1
这非常的重要,所以一定要记住:在幕后,AngularJS实际上是在调用前面出现的代码(就是$provide.provider的版本)。从字面上来说,这两种方法基本上没有差别。value方法也一样 – 如果我们需要从$get函数(也就是我们的factory函数)返回的值永远相同的话,我们可以使用value方法来编写更少的代码。例如如果我们的greeting服务总是返回相同的函数,我们可以使用value来进行定义:

代码laycode - v1.1
再一次申明,以上两种方式的效果完全一样 – 只不过是代码的量不同而已。

现在你可能已经注意到了我们使用的烦人的

代码laycode - v1.1
代码了。由于定义一个新的provider是如此的常用,AngularJS在模块对象上直接暴露了provider方法,以此来减少代码的输入量:

代码laycode - v1.1
上面的代码和前面app.config(...)这样?嗦的写法完全相同。

除了上面提到的可以注入的东西之外,还有一个constant方法。基本上,它和value的用法一致。我们会在后面来讨论两者的不同点。

为了巩固前面的学习成果,下面所有的代码所做的都是同一件事情:

代码laycode - v1.1
注入器($injector)
注入器负责从我们通过$provide创建的服务中创建注入的实例。只要你编写了一个带有可注入性的参数,你都能看到注入器是如何运行的。每一个AngularJS应用都有唯一一个$injector,当应用启动的时候它被创造出来,你可以通过将$injector注入到任何可注入函数中来得到它($injector知道如何注入它自己!)。

一旦你拥有了$injector,你可以动过调用get函数来获得任何一个已经被定义过的服务的实例。例如:

代码laycode - v1.1
注入器同样也负责将服务注入到函数中;例如,你可以魔法般的将服务注入到任何函数中,只要你使用了注入器的invoke方法:

代码laycode - v1.1
如果注入器只是创建一个服务的实例一次的话,那么它也没什么了不起的。它的厉害之处在于,他能够通过服务名称缓存从一个provider中返回的任何东西,当你下一次再使用这个服务时,你将会得到同一个对象。

因此,你可以通过调用$injector.invike将服务注入到任何函数中也是合情合理的了。包括:

控制器定义函数
指令定义函数
过滤器定义函数
provider中的$get方法(也就是factory函数)
由于constant和value总是返回一个静态值,它们不会通过注入器被调用,因此你不能在其中注入任何东西。

配置provider
你可能会感到困惑:既然factorry和value能够节省那么多的代码,为什么还有人要使用provider。答案是provider允许我们进行一些配置。在前面我们已经提到过当你通过provider(或者其他简写方法)创建一个服务时,你实际上创建了一个新的provider,它将定义你的服务如何被创建。我们没有提到的是,这些provider可以被注入到config函数中,你可以和它们进行一些交互。

首先,AngularJS分两个阶段运行你的应用 – config阶段和run阶段。config阶段是你设置任何的provider的阶段。它也是你设置任何的指令,控制器,过滤器以及其它东西的阶段。在run阶段,AngularJS会编译你的DOM并启动你的应用。

你可以在myMod.config和myMod.run中添加任何代码 – 这两个函数分别在两个阶段运行。正如我们看到的,这些函数都是可以被注入的 – 我们在第一个例子中注入了内建的$provide函数。然而,值得注意的是在config阶段,只有provider能被注入(只有两个例外是$provide和$injector)。

例如,下面的代码就是错误的写法:

代码laycode - v1.1
有一个例外:constant,由于它们不能被改变,因此它不能被注入到config中(这就是它和value之间的不同之处)。它们只能通过名字被获取。

无论何时你为一个服务定义了一个provider,这个provider的名字都是serviceProvider。在这里service是服务的名字。现在我们可以使用provider的力量来做一些更复杂的事情了!

代码laycode - v1.1
现在我们在provider中拥有了一个叫做setText的函数,我们可以使用它来自定义我们alert的内容;我们可以再config中访问这个provider,调用setText方法并自定义我们的service。当我们最终运行我们的应用时,我们可以获取greeting服务,然后你会看到我们自定义的行为起作用了。

控制器($controller)
控制器函数是可以被注入的,但是控制器本身是不能被注入到任何东西里面去的。这是因为控制器不是通过provider创建的。然而,有一个内建的AngularJS服务叫做1$controller,它负责设置你的控制器。当你调用myMod.controller(…)时,你实际上是访问了这个服务的provider,就像上面的例子一样。

例如,当你像下面一样定义了一个控制器时:

代码laycode - v1.1
你实际上做的是下面这件事:

代码laycode - v1.1
当Angular需要创建一个你的控制的实例时,它会使用$controller服务(它反过来会使用$injector来调用你的控制器以便它能够被注入依赖项)。

过滤器和指令
filter和directive和controller的运行方式相同;filter会使用一个叫做$filter的服务以及它的provider $filterProvider,而directive使用一个叫做$compile的服务以及它的provider $compileProvidr。下面是相应的文档:

其中,myMod.filter和myMod.directive分别是这些服务的简写。

总结
总结一下,任何能够被$injector.invoke调用的函数都是能被注入的。包括,但不限于下面的这些:

控制器
指令
factory
过滤器
provider中的$get函数
provider函数
服务
provider创建的新服务都可以用来注入。包括:

constant
factory
provider
service
value
另外,内建的服务$controller和$filter也可以被注入,同时你也可以使用这些服务来获得新的过滤器和控制器。

本文译自Understanding Dependency Injection,原文地址https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection
Jan 20
在angularjs的sap项目中使用了requirejs做模块管理,rjs参与压缩,在配置了很多次path之后压缩没有问题,发现压缩后的文件一直报错,最后取消了uglify的混淆解决问题,参考了以下文档,感谢作者分享

我在项目使用了AngularJS框架,用RequireJS做异步模块加载(AMD),在做文件合并压缩时,遇到了一些坑,有些只是解决了,但不明白原因。

那些坑
1. build.js里面的paths必须跟main.js里面的保持一致。

这个build.js就是r.js使用的配置文件,而main.js就是RequireJS的main文件。在合并压缩时候,build.js文件里面也需要写paths,而且还是跟main.js一样,我很奇怪为什么就不能识别main里面的require.config的paths,省得合并的时候还要将paths拷贝过来(我试过build.js里面没有paths,是不能合并的)。(-_-!!!)

2. 某些依赖库需要写整个相对路径才能做合并。

在项目里, 我使用一个叫layer的第三方库(库是以requireJS define写的),一开始只做开发时候,在paths配置了路径后,使用此库只需要用个简称(define依赖时候)。 但在做合并时候,竟然提示文件不存在(因为直接拿简称去拼文件地址了),无奈之下只能修改这个库的使用办法,全部使用到这个库的都写整个相对路径,这个时候开发和做合并才没有错。

3. 合并之后可以运行,加上压缩就不可以。

这个是最严重问题,最严重问题,最严重问题。在文件合并压缩后,使用文件时候,AngularJS运行就不正常了,总是报模块初始化失败,Failed to instantiate module common due to: Error: [$injector:unpr] Unknown provider: e,如下图。
Highslide JS


很关键的一个点就是,不压缩可以用,一旦压缩了(用了默认的压缩),使用就会报错。所以思考必定某些东西被“压坏”了,网上某些文章都说是需要下面这样写AngularJS cntroller、directive等,使用的服务用字符串定义。

commonModule.controller( "broswerCtrl" ,["$scope" ,"$sce" , function ($scope,$sce){
可是我的整个应用就是这样定义,并没有给它注入错误的机会。[b]最后在无奈之下,就只能配置mangle: false,不混淆变量名,这样做后,合并压缩的文件就能正确使用了!!!配置文件如下


[/b]PS:简单说法就是,合并压缩可以,变量名不能混淆(总觉得怪怪的),感觉问题暂时无解。

4. 第二层的require,做合并的时候,是合并不出来。

例如在mian.js里面这样加载模块,在合并时候会发现第二层的require并没有被合并到。

这时需要在build.js加findNestedDependencies: true, 这时才会合并第二层。

合并准备

安装nodejs

文件合并压缩基于nodejs,所以先安装nodejs,下载地址: http://blog.nodejs.org/2013/07/25/node-v0-10-15-stable/

下载r.js

r.js配合requirejs模块写法对文件进行合并,压缩,下载地址: https://github.com/jrburke/r.js

简单配置

配置文件最好写一个build.js,如下:

这里就讲几个关键属性:

baseUrl:所有的模块(般就是js)都相对于这个路径存在。

optimize:优化脚本文件的方式,有下面5种取值方式。

uglify:(默认) 用UglifyJS压缩。
uglify2: 用UglifyJS2( 2.1.2+)压缩。
closure: 使用Google's Closure Compiler 简单优化模式压缩文件, 仅在优化工具使用Java有效。
closure.keepLines:跟closure参数一样, 只不过保留换行符。
none: 不做压缩。
findNestedDependencies:寻找require()里面的require或define调用的依赖。

PS:配置属性还有很多,就不一细细说了,有篇文章写得很详尽,地址:http://segmentfault.com/a/1190000002403806#articleHeader37

当文件配置好后,就执行命令合并压缩

node r.js -o build.js
总结

RequireJS模块的合并压缩还是比较简单的,但是遇到AngularJS,在压缩方面就有些问题了,目前没找到什么更好办法。
Nov 2
关于控制器如何通信的问题,是不少刚接触angulr的同学想知道的。总的来说,angular控制器通信的方式有三种:
1,利用作用域继承的方式。即子控制器继承父控制器中的内容

2,基于事件的方式。即$on,$emit,$boardcast这三种方式

3,服务方式。写一个服务的单例然后通过注入来使用

利用作用域的继承方式

由于作用域的继承是基于js的原型继承方式,所以这里分为两种情况,当作用域上面的值为基本类型的时候,修改父作用域上面的值会
影响到子作用域,反之,修改子作用域只会影响子作用域的值,不会影响父作用域上面的值;如果需要父作用域与子作用域共享一个值
的话,就需要用到后面一种,即作用域上的值为对象,任何一方的修改都能影响另一方,这是因为在js中对象都是引用类型。
Aug 25

While delivering software projects for startups, we’ve come to love AngularJS. We’ve also come to struggle with clean modularity, both the parts that Angular does really well, and the parts that are somewhat missing. RequireJS does a great job where Angular leaves some things to be desired, but using them together is not entirely trivial. What follows is our take at the problem.

Why?

Working with Angular you could worry about a good way to organize code. There are already great how-tos on that, check out this mainly theoretical post by Brian Ford and this practical guide by Cliff Meyers if you haven’t already. I’ll share the way I’m managing code in Angular applications with RequireJS.

Continue reading if you want to:

        
  • stop worrying about including script tags in the right order when building Angular apps;
  •     
  • to load your javascript asynchronously;
  •     
  • to compile code into single minified js file;

Who?

I assume that you already know what AngularJS is and that you’ve at least heard of AMD and RequireJS. To illustrate the approach I’ll first enable RequireJS for Angular Seed and explain process. Angular Seed structures code by splitting files by type and so will I. It’s also possible to apply this approach if you write modules by entities (you’ll see it from app.controllersmodule implementation).

How?

Angular Seed Project

Let’s check how Angular Seed structures code. Check out the example in your browser or on github (copied from Seed):

        
  • app.js file to bootstrap and set app config;
  •     
  • actual implementation files – controllers, services, directives and filters;
  •     
  • index.html with all script tags included in right order;
  •     
  • or index-async.html that makes use of angular-loader.js and 3-rd party $script loader library to load dependencies asyncronously.

Let’s start the party.

Add RequireJS

Checkout the example in your browser or on github.

Installing dependencies

I used bower to do this for me. See bower.json file:

{  "name": "AngularJS + RequireJS Example",  "version": "0.1",  "main": "index.html",  "ignore": [    "**/.*",    "libs"  ],  "dependencies": {    "angular": "latest",    "requirejs": "latest",    "requirejs-domready": "latest"  }}

Put the .bowerrc file next to bower.json, run bower install and – poof, we have all we need under libs folder.

index.html

Destruction is a good start. Open Angular Seed’s index.html and remove all the <script> tags. Looks cleaner, doesn’t it? Now switch to creation mode and add single script before closing </body> that will load RequireJS and instruct it to look for config in js/main.js with the data-main attribute:

<!doctype html><html lang="en"><head>  <meta charset="utf-8">  <title>My AngularJS AngularJS + RequireJS App</title>  <link rel="stylesheet" href="css/app.css"></head><body>  <ul class="menu">    <li><a href="#/view1">view1</a></li>    <li><a href="#/view2">view2</a></li>  </ul><div data-ng-view></div><div>Angular Require seed app: v<span app-version></span></div><script src="lib/requirejs/require.js" data-main="js/main.js"></script></body></html>

That’s all there’s to it. You can close index.html now, as there is nothing more we need to add to it.

main.js

Time to setup RequireJS config.

require.config({  // alias libraries paths    paths: {        'domReady': '../lib/requirejs-domready/domReady',        'angular': '../lib/angular/angular'    },    // angular does not support AMD out of the box, put it in a shim    shim: {        'angular': {            exports: 'angular'        }    },    // kick start application    deps: ['./bootstrap']});

What just happened? In paths we set aliases for the libraries and plugins used, then we defined that angular should be shimmed and thatbootstrap.js should be loaded to start the application.

bootstrap.js

We’re bootstrapping angular manually now, that’s what bootstrap.js is for. Note that you don’t need ng-app in your html anymore. Also routes.js, which contains angular routes configuration is included into dependencies list.

Note that in this require module we almost have no use of asynchronous loading and we’ll always have chain of angular -> app -> routes, as they depend on each other: angular needs to be present on a page before setting up application module, which is required to exist when defining routes config.

/** * bootstraps angular onto the window.document node */define([    'require',    'angular',    'app',    'routes'], function (require, ng) {    'use strict';    require(['domReady!'], function (document) {        ng.bootstrap(document, ['app']);    });});

We use domReady RequireJS plugin to make sure that DOM is ready when we start the app. Note that before doing so we’re loading the app.jsdependency, in there the main application is defined.

app.js

app.js wraps the definition of the top-level app module and loads the dependencies of its submodules.

define([    'angular',    './controllers/index',    './directives/index',    './filters/index',    './services/index'], function (ng) {    'use strict';    return ng.module('app', [        'app.services',        'app.controllers',        'app.filters',        'app.directives'    ]);});

We agreed to have 4 modules by files types: controllers, directives, filters, services – we require these modules to be loaded before defining the main module.

routes.js

Top level routes definition lives here. It is also possible to have modules to set up their own routes (this case is omitted for now in favour of simplicity).

define(['./app'], function (app) {    'use strict';    return app.config(['$routeProvider', function ($routeProvider) {        $routeProvider.when('/view1', {            templateUrl: 'partials/partial1.html',            controller: 'MyCtrl1'        });        $routeProvider.when('/view2', {            templateUrl: 'partials/partial2.html',            controller: 'MyCtrl2'        });        $routeProvider.otherwise({            redirectTo: '/view1'        });    }]);});

Module structure

A module consists of 3 parts:

        
  • definition;
  •     
  • component;
  •     
  • loader.

Let’s use the app.controllers module as example.

module definition (controllers/module.js)

It’s just like top level app.js: it defines a module.

define(['angular'], function (ng) {    'use strict';    return ng.module('app.controllers', []);});

This file will be used by the module components to attach themselves to (see next section).

module loader (controllers/index.js)

That’s just an empty define block with all module components included. You don’t need to mention module.js here as it’s already required by components. Loader is included as dependency of top level app module. And that’s actually how RequireJS knows about files to load.

define([    './my-ctrl-1',    './my-ctrl-2'], function () {});

module components (controllers/my-ctrl-1.js)

In the case with the app.controllers module it’ll be controllers. Example of controller wrapped in define is:

define(['./module'], function (controllers) {    'use strict';    controllers.controller('MyCtrl1', [function ($scope) {}]);});

Note that we used reference to ./module.js to attach component to its module.

Conclusion

That’s it. Now you have working Angular application powered by RequireJS. You can enjoy the power of not tracking the order of your scripts anymore and you get some powerful minification tooling to boot.

In next articles I’ll show you how to test this application properly, how to compile it into single file and automate workflows with grunt. All this is already enabled in StarterSquad Angular + Require Seed check it out if you can’t wait (I’m a slow typist).

About StarterSquad

StarterSquad is a community of distributed development teams consisting of freelance developers. We specialize in startups and lean innovation. If you want to know more, read more about how we work and if you need any help with Angular, checkout my team.

Tags: , ,
Nov 30

2014 十月底在巴黎举行的ng-europe大会上,Angular团队为与会者介绍了即将到来的AngularJS 2.0版本的细节。新版本对1.x版本进行了重大的颠覆,当前还没有任何迁移指南,此外它还是基于一个名为AtScript的新语言进行开发的。

对于熟悉Angular 1.X版本的开发者来说,他们将看到一个完全不同的框架,并且必须学习一种新的架构。在一堂关于版本2.0的变更的讲座中,Igor Minar 和 Tobias Bosch介绍了新的模板语法:

http://cdn3.infoqstatic.com/styles/i/green_border.jpg) -29px 0px repeat-y rgb(244, 244, 244);"><input type="text" [value]="firstName"><button (click)="addPerson()">Add</button>

这种新语法将数据绑定到元素的属性(property)上,而不是特性(attribute)上。这就允许你使用以下语法:

http://cdn3.infoqstatic.com/styles/i/green_border.jpg) -29px 0px repeat-y rgb(244, 244, 244);"><input type="checkbox" [checked]="someProperty">

看上去类似于标准的HTML,但这个复选框元素不会暴露出checked特性。新的模板引擎将数据绑定到元素的属性上,即使这些属性并非由DOM所暴露出的特性。

与新架构引起的其它剧变相比,新的模板语法只是一个相对较小的改动。与会者之一的Michael Bromley描述了一些新版本的一些破坏性改动,版本2.0取消了1.X中的以下概念

        
  • 控制器(Controller)
  •     
  • (Directive定义对象)
  •     
  • $scope
  •     
  • angular.module
  •     
  • jqLite
May 28
开发nodejs+angularjs的应用,debug时总要清缓存,着实蛋疼,设置下chrome就搞定了,如下:
在使用 Google Chrome 浏览器调试 js 时,会发现修改完 js 不会立即生效,这是由于 chrome 浏览器缓存的原因,而在火狐下没有这个问题。经常使用 chrome 浏览器调试 js 的朋友一定会发现 chrome 下调试 js 更加顺手,那么就让我们看看怎么在 chrome 下禁止缓存。

按F12(Ctrl+Shift+J 或 Ctrl+Shift+I)打开开发者工具,找到右下角的图标,如下:
Highslide JS
Highslide JS
Pages: 1/2 First page 1 2 Next page Final page [ View by Articles | List ]