angularjs动态添加div怎么实现不同控制器下的div绑定

详解AngularJS控制器的使用
转载 & & 作者:彼岸花在开
这篇文章主要为大家详细介绍了AngularJS控制器的使用方法,感兴趣的小伙伴们可以参考一下
控制器在Angularjs中的作用是增强视图,它实际就是一个函数,用来向视图中的作用域添加额外的功能,我们用它来给作用域对象设置初始状态,并添加自定义行为。
当我们在页面上创建一个控制器时,Angularjs会生成并传递一个$scope给这个控制器,由于Angularjs会自动实例化控制器,所以我们只需要写构造函数即可。下面的例子展示了控制器初始化:
function my Controller($scope){
$scope.msg="hello,world!";
上面这个创建控制器的方法会污染全局命名空间,更合理的办法是创建一个模块,然后在模块中创建控制器,如下:
var myApp=angular.module("myApp",[]);
myApp.controller("myController",function($scope){
$scope.msg="hello,world!";
用内置指令ng-click可以将按钮、链接等其他任何DOM元素同点击事件进行绑定。ng-click指令将浏览器中的mouseup事件,同设置在DOM元素上的事件处理程序绑定在一起(例如,当浏览器在某个DOM元素上触发了点击事件,函数就会被调用)。和前面的例子类似,绑定看起来是这样的:
&div ng-controller="FirstController"&
&h4&The simplest adding machine ever&/h4&
&button ng-click="add(1)" class="button"&Add&/button&
&a ng-click="subtract(1)" class="button alert"&Subtract&/a&
&h4&Current count: {{ counter }}&/h4&
按钮和链接都被绑定在了内部$scope的一个操作上,当点击任何一个元素时AngularJS都会调用相应的方法。注意,当设置调用哪个函数时,会同时用括号传递一个参数(add(1))
app.controller('FirstController', function($scope) {
$scope.counter = 0;
$scope.add = function(amount) { $scope.counter += };
$scope.subtract = function(amount) { $scope.counter -= };
Angularjs与其他框架的最大区别在于,控制器并不适合来执行DOM操作、格式化或数据操作,以及除存储数据模型之外的状态维护操作,它只是视图和$scope之间的桥梁。
控制器嵌套(作用域包含作用域)
AngularJS应用的任何一个部分,无论它渲染在哪个上下文中,都有父级作用域存在。对于ng-app所处的层级来讲,它的父级作用域就是$rootScope。
默认情况下,AngularJS在当前作用域中无法找到某个属性时,便会在父级作用域中进行查找。如果AngularJS找不到对应的属性,会顺着父级作用域一直向上寻找,直到抵达$rootScope为止。如果在$rootScope中也找不到,程序会继续运行,但视图无法更新。
通过例子来看一下这个行为。创建一个ParentController,其中包含一个user对象,再创建一个ChildController来引用这个对象:
app.controller('ParentController', function($scope) {
$scope.person = {greeted: false};
app.controller('ChildController', function($scope) {
$scope.sayHello = function() {
$scope.person.name = 'Ari Lerner';
如果我们将ChildController置于ParentController内部,那ChildController的$scope对象的父级作用域就是ParentController的$scope对象。根据原型继承的机制,我们可以在子作用域中访问ParentController的$scope对象。
&div ng-controller="ParentController"&
&div ng-controller="ChildController"&
&a ng-click="sayHello()"&Say hello&/a&
{{ person }}
以上就是本文的全部内容,希望对大家的学习有所帮助,帮助大家熟悉AngularJS控制器。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)Angular数据双向绑定
AngularJS诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google的多款产品当中。AngularJS有着诸多特性,最为核心的是:MVVM、模块化、自动化双向数据绑定、语义化标签、依赖注入等等。
一.什么是数据双向绑定
Angular实现了双向绑定机制。所谓的双向绑定,无非是从界面的操作能实时反映到数据,数据的变更能实时展现到界面。
一个最简单的示例就是这样:
&div ng-controller="CounterCtrl"&
&span ng-bind="counter"&&/span&
&button ng-click="counter++"&increase&/button&
&/div&function CounterCtrl($scope) {
$scope.counter = 1;
这个例子很简单,每当点击一次按钮,界面上的数字就增加一。
二.数据双向绑定原理
1.深入理解
实现用户控制手机列表显示顺序的特性。动态排序可以这样实现,添加一个新的模型属性,把它和迭代器集成起来,然后让数据绑定完成剩下的事情。
模板(app/index.html)
Search: &input ng-model="query"&
&select ng-model="orderProp"&
&option value="name"&Alphabetical&/option&
&option value="age"&Newest&/option&
&ul class="phones"&
&li ng-repeat="phone in phones | filter:query | orderBy:orderProp"&
{{phone.name}}
&p&{{phone.snippet}}&/p&
在index.html中做了如下更改:
首先,增加了一个叫做orderProp的&select&标签,这样用户就可以选择提供的两种排序方法。
然后,在filter过滤器后面添加一个orderBy过滤器用其来处理进入迭代器的数据。orderBy过滤器以一个数组作为输入,复制一份副本,然后把副本重排序再输出到迭代器。AngularJS在select元素和orderProp模型之间创建了一个双向绑定。而后,orderProp会被用作orderBy过滤器的输入。
什么时候数据模型发生了改变(比如用户在下拉菜单中选了不同的顺序),AngularJS的数据绑定会让视图自动更新。没有任何笨拙的DOM操作。
控制器(app/js/controllers.js)
function PhoneListCtrl($scope) {
$scope.phones = [
{"name": "Nexus S",
"snippet": "Fast just got faster with Nexus S.",
"age": 0},
{"name": "Motorola XOOM& with Wi-Fi",
"snippet": "The Next, Next Generation tablet.",
"age": 1},
{"name": "MOTOROLA XOOM&",
"snippet": "The Next, Next Generation tablet.",
$scope.orderProp = 'age';
修改了phones模型&& 手机的数组 &&为每一个手机记录其增加了一个age属性。根据age属性来对手机进行排序。在控制器代码里加了一行让orderProp的默认值为age。如果我们不设置默认值,这个模型会在用户在下拉菜单选择一个顺序之前一直处于未初始化状态。
现在我们该好好谈谈双向数据绑定了。注意到当应用在浏览器中加载时,&Newest&在下拉菜单中被选中。这是因为我们在控制器中把orderProp设置成了&age&。所以绑定在从我们模型到用户界面的方向上起作用&&即数据从模型到视图的绑定。现在当你在下拉菜单中选择&Alphabetically&,数据模型会被同时更新,并且手机列表数组会被重新排序。这个时候数据绑定从另一个方向产生了作用&&即数据从视图到模型的绑定。
2.原理分析
下面的原理想法实际上很基础,可以被认为是3步走计划:
我们需要一个UI元素和属性相互绑定的方法
我们需要监视属性和UI元素的变化
我们需要让所有绑定的对象和元素都能感知到变化
还是有很多方法能够实现上面的想法,有一个简单有效的方法就是使用PubSub模式。 这个思路很简单:我们使用数据特性来为HTML代码进行绑定,所有被绑定在一起的JavaScript对象和DOM元素都会订阅一个PubSub对象。只要JavaScript对象或者一个HTML输入元素监听到数据的变化时,就会触发绑定到PubSub对象上的事件,从而其他绑定的对象和元素都会做出相应的变化。
3.发布者-订阅者模式(PubSub模式)
设计该模式背后的主要动力是促进形成松散耦合。在这种模式中,并不是一个对象调用另一个对象的方法,而是一个对象订阅另一个对象的特定活动并在状态改变后获得通知。订阅者也称为观察者,而补观察的对象称为发布者或主题。当发生了一个重要的事件时,发布者将会通知(调用)所有订阅者并且可能经常以事件对象的形式传递消息。
假设有一个发布者paper,它每天出版报纸及月刊杂志。订阅者joe将被通知任何时候所发生的新闻。
该paper对象需要一个subscribers属性,该属性是一个存储所有订阅者的数组。订阅行为只是将其加入到这个数组中。当一个事件发生时,paper将会循环遍历订阅者列表并通知它们。通知意味着调用订阅者对象的某个方法。故当用户订阅信息时,该订阅者需要向paper的subscribe()提供它的其中一个方法。
paper也提供了unsubscribe()方法,该方法表示从订阅者数组(即subscribers属性)中删除订阅者。paper最后一个重要的方法是publish(),它会调用这些订阅者的方法,总而言之,发布者对象paper需要具有以下这些成员:
①subscribers 一个数组
②subscribe() 将订阅者添加到subscribers数组中
③unsubscribe() 从subscribers数组中删除订阅者
④publish() 循环遍历subscribers数组中的每一个元素,并且调用他们注册时所提供的方法
所有这三种方法都需要一个type参数,因为发布者可能触发多个事件(比如同时发布一本杂志和一份报纸)而用户可能仅选择订阅其中一种,而不是另外一种。
由于这些成员对于任何发布者对象都是通用的,故将它们作为独立对象的一个部分来实现是很有意义的。那样我们可将其复制到任何对象中,并将任意给定对象变成一个发布者。
三.用jQuery做一个简单的实现
对于DOM事件的订阅和发布,用jQuery实现起来是非常简单的,接下来我们就是用Jquery比如下面:
function DataBinder( object_id ) {
// Use a jQuery object as simple PubSub
var pubSub = jQuery({});
// We expect a `data` element specifying the binding
// in the form: data-bind-&object_id&="&property_name&"
var data_attr = "bind-" + object_id,
message = object_id + ":change";
// Listen to change events on elements with the data-binding attribute and proxy
// them to the PubSub, so that the change is "broadcasted" to all connected objects
jQuery( document ).on( "change", "[data-" + data_attr + "]", function( evt ) {
var $input = jQuery( this );
pubSub.trigger( message, [ $input.data( data_attr ), $input.val() ] );
// PubSub propagates changes to all bound elements, setting value of
// input tags or HTML content of other tags
pubSub.on( message, function( evt, prop_name, new_val ) {
jQuery( "[data-" + data_attr + "=" + prop_name + "]" ).each( function() {
var $bound = jQuery( this );
if ( $bound.is("input, textarea, select") ) {
$bound.val( new_val );
$bound.html( new_val );
return pubS
对于上面这个实现来说,下面是一个User模型的最简单的实现方法:
function User( uid ) {
var binder = new DataBinder( uid ),
attributes: {},
// The attribute setter publish changes using the DataBinder PubSub
set: function( attr_name, val ) {
this.attributes[ attr_name ] =
binder.trigger( uid + ":change", [ attr_name, val, this ] );
get: function( attr_name ) {
return this.attributes[ attr_name ];
_binder: binder
// Subscribe to the PubSub
binder.on( uid + ":change", function( evt, attr_name, new_val, initiator ) {
if ( initiator !== user ) {
user.set( attr_name, new_val );
现在我们如果想要将User模型属性绑定到UI上,我们只需要将适合的数据特性绑定到对应的HTML元素上。
// javascript
var user = new User( 123 );
user.set( "name", "Wolfgang" );
&input type="number" data-bind-123="name" /&
这样输入值会自动映射到user对象的name属性,反之亦然。到此这个简单实现就完成了。
四.Angular实现数据双向绑定
Angular主要通过scopes实现数据双向绑定。AngularJS的scopes包括以下四个主要部分:
digest循环以及dirty-checking,包括$watch,$digest,和$apply。Scope继承 - 这项机制使得我们可以创建scope继承来分享数据和事件。对集合 & 数组和对象 & 的有效dirty-checking。事件系统 - $on,$emit,以及$broadcast。
我们主要讲解第一条Angular数据绑定是怎么实现的。
1.digest循环以及dirty-checking,包括$watch,$digest,和$apply
①浏览器事件循环和Angular.js扩展
我们的浏览器一直在等待事件,比如用户交互。假如你点击一个按钮或者在输入框里输入东西,事件的回调函数就会在javascript解释器里执行,然后你就可以做任何DOM操作,等回调函数执行完毕时,浏览器就会相应地对DOM做出变化。 Angular拓展了这个事件循环,生成一个有时成为angular context的执行环境(这是个重要的概念)。
②$watch 队列($watch list)
每次你绑定一些东西到你的UI上时你就会往$watch队列里插入一条$watch。想象一下$watch就是那个可以检测它监视的model里时候有变化的东西。
当我们的模版加载完毕时,也就是在linking阶段(Angular分为compile阶段和linking阶段---译者注),Angular解释器会寻找每个directive,然后生成每个需要的$watch。
③$digest循环
还记得我前面提到的扩展的事件循环吗?当浏览器接收到可以被angular context处理的事件时,$digest循环就会触发。这个循环是由两个更小的循环组合起来的。一个处理evalAsync队列,另一个处理$watch队列。 这个是处理什么的呢?$digest将会遍历我们的$watch,然后询问它是否有属性和值的变化,直$watch队列都检查过。
这就是所谓的dirty-checking。既然所有的$watch都检查完了,那就要问了:有没有$watch更新过?如果有至少一个更新过,这个循环就会再次触发,直到所有的$watch都没有变化。这样就能够保证每个model都已经不会再变化。记住如果循环超过10次的话,它将会抛出一个异常,防止无限循环。 当$digest循环结束时,DOM相应地变化。
例如: controllers.js
app.controller('MainCtrl', function() {
$scope.name = "Foo";
$scope.changeFoo = function() {
$scope.name = "Bar";
index.html
{{ name }}
&button ng-click="changeFoo()"&Change the name&/button&
这里我们有一个$watch因为ng-click不生成$watch(函数是不会变的)。
我们按下按钮
浏览器接收到一个事件,进入angular context(后面会解释为什么)。
$digest循环开始执行,查询每个$watch是否变化。
由于监视$scope.name的$watch报告了变化,它会强制再执行一次$digest循环。
新的$digest循环没有检测到变化。
浏览器拿回控制权,更新与$scope.name新值相应部分的DOM。
这里很重要的(也是许多人的很蛋疼的地方)是每一个进入angular context的事件都会执行一个$digest循环,也就是说每次我们输入一个字母循环都会检查整个页面的所有$watch。
④通过$apply来进入angular context
谁决定什么事件进入angular context,而哪些又不进入呢?$apply!
如果当事件触发时,你调用$apply,它会进入angular context,如果没有调用就不会进入。现在你可能会问:刚才的例子里我也没有调用$apply,为什么?Angular为你做了!因此你点击带有ng-click的元素时,时间就会被封装到一个$apply调用。如果你有一个ng-model="foo"的输入框,然后你敲一个f,事件就会这样调用$apply("foo = 'f';")。
Angular什么时候不会自动为我们$apply呢?这是Angular新手共同的痛处。为什么我的jQuery不会更新我绑定的东西呢?因为jQuery没有调用$apply,事件没有进入angular context,$digest循环永远没有执行。
2.具体实现
AngularJS的scopes就是一般的JavaScript对象,在它上面你可以绑定你喜欢的属性和其他对象,然而,它们同时也被添加了一些功能用于观察数据结构上的变化。这些观察的功能都由dirty-checking来实现并且都在一个digest循环中被执行。
①Scope 对象
创建一个test/scope_spec.js文件,并将下面的测试代码添加到其中:
test/scope_spec.js
/* jshint globalstrict: true */
/* global Scope: false */
'use strict';
describe("Scope", function() {
it("can be constructed and used as an object", function() {
var scope = new Scope();
scope.aProperty = 1;
expect(scope.aProperty).toBe(1);
这个测试用来创建一个Scope,并在它上面赋一个任意值。我们可以轻松的让这个测试通过:创建src/scope.js文件然后在其中添加以下内容:
src/scope.js
/* jshint globalstrict: true */
'use strict'; function Scope() {
在这个测试中,我们将一个属性(aProperty)赋值给了这个scope。这正是Scope上的属性运行的方式。它们就是正常的JavaScript属性,并没有什么特别之处。这里你完全不需要去调用一个特别的setter,也不需要对你赋值的类型进行什么限制。真正的魔法在于两个特别的函数:$watch和$digest。我们现在就来看看这两个函数。
②监视对象属性:$watch和$digest
$watch和$digest是同一个硬币的两面。它们二者同时形成了$digest循环的核心:对数据的变化做出反应。
为了实现这一块功能,我们首先来定义一个测试文件并断言你可以使用$watch来注册一个监视器,并且当有人调用了$digest的时候监视器的监听函数会被调用。
在scope_spec.js文件中添加一个嵌套的describe块。并创建一个beforeEach函数来初始化这个scope,以便我们可以在进行每个测试时重复它:
test/scope_spec.js
describe("Scope", function() {
it("can be constructed and used as an object", function() { var scope = new Scope();
scope.aProperty = 1;
expect(scope.aProperty).toBe(1);
describe("digest", function() {
beforeEach(function() { scope = new Scope();
it("calls the listener function of a watch on first $digest", function() { var watchFn = function() { return 'wat'; };
var listenerFn = jasmine.createSpy();
scope.$watch(watchFn, listenerFn);
scope.$digest();
expect(listenerFn).toHaveBeenCalled();
在上面的这个测试中我们调用了$watch来在这个scope上注册一个监视器。我们现在对于监视函数本身并没有什么兴趣,因此我们随便提供了一个函数来返回一个常数值。作为监听函数,我们提供了一个Jasmine Spy。接着我们调用了$digest并检查这个监听器是否真正被调用。
首先,这个Scope需要有一些地方去存储所有被注册的监视器。我们现在就在Scope构造函数中添加一个数组存储它们:
src/scope.js
function Scope(){
this.$$watchers = [];
上面代码中的$$前缀在AngularJS框架中被认为是私有变量,它们不应该在应用的外部被调用。
现在我们可以来定义$watch函数了。它接收两个函数作为参数,并且将它们储存在$$watchers数组中。我们想要每一个Scope对象都拥有这个函数,因此我们将它添加到Scope的原型中:
src/scope.js
Scope.prototype.$watch = function(watchFn, listenerFn) {
var watcher = {
watchFn: watchFn,
listenerFn: listenerFn
this.$$watchers.unshift(watcher);
最后我们应该有一个$digest函数。现在,我们来定义一个$digest函数的简化版本,它仅仅只是会迭代所有的注册监视器并调用它们的监听函数:
digest能够持续的迭代所有监视函数,直到被监视的值停止变化。多做几次digest是我们能够获得运用于监视器并依赖于其他监视器的变化。
首先,我们新建名为$$digestOnce,并且调整它以便它能够在所有监视器上运行一遍,然后返回一个布尔值来说明有没有任何变化:
src/scope.js
Scope.prototype.$$digestOnce = function(){
var length = this.$$watchers.
var watcher, newValue, oldValue,
while(length--){
watcher = this.$$watchers[length];
newValue = watcher.watchFn(this);
oldValue= watcher.
if(newValue !== oldValue){
watcher.last == newV
watcher.listenerFn(newValue, oldValue, this);
dirty = true;
接着,我们重定义$digest以便它能够运行&外循环&,在变化发生时调用$$digestOnce:
src/scope.js
Scope.prototype.$digest = function(){
dirty = this.$$digestOnce();
} while (dirty);
很多人对Angular的脏检测机制感到不屑,推崇基于setter,getter的观测机制,在我看来,这只是同一个事情的不同实现方式,两者是各有优劣。
-------------------------------------------------------------------------------------------------------------------------------------
转载需注明转载字样,标注原作者和原博文地址。
更多阅读:
阅读(...) 评论()21被浏览1,540分享邀请回答35 条评论分享收藏感谢收起/* index.html */
&h2&test&/h2&
&div class="row"&
&div class="span4"&
&div class="well" ui-view="viewA"&&/div&
&div class="span4"&
&div class="well" ui-view="viewB"&&/div&
/* app.js */
var myapp = angular.module('myapp', ["ui.router", 'myApp.controllers', 'myApp.services'])
myapp.config(function($stateProvider){
$stateProvider
.state('index', {
"viewA": {
templateUrl: 'AView.html',
controller: 'ACtrl'
"viewB": {
templateUrl: 'BView.html',
controller: 'BCtrl'
/* AView.html */
This is View A.
&button ng-click="add()"&Add&/button&
name : {{myData.name}}
email : {{myData.email}}
id : {{myData.id}}
/* BView.html */
This is View B.
name : {{myData.name}}
email : {{myData.email}}
id : {{myData.id}}
/* services.js */
var myApp = angular.module('myApp.services', []);
myApp.service('dataService', ['dataPool',
function(dataPool){
var self = this;
self.myData = {}
self.myData = dataPool.getData();
self.id = dataPool.getData().id;
self.add = function() {
self.id++;
dataPool.setData_id(self.id);
myApp.factory('dataPool', function($rootScope){
var data={
name: 'ShangSinian',
email: '',
setData_id:function(id){
data.id = id;
getData:function(){
return data;
/* controllers.js */
angular.module('myApp.controllers', ['myApp.services'])
.controller('ACtrl', ['$scope','dataService',
'dataPool',
function( $scope , dataService ,dataPool) {
var self = this;
$scope.myData = dataService.myData;
self.id = dataPool.getData().id;
$scope.add = dataService.add;
.controller('BCtrl', ['$scope','dataService',
function($scope,dataService) {
var self = this;
$scope.myData = dataService.myData;
05 条评论分享收藏感谢收起写回答2 个回答被折叠()AngularJs开发——指令与控制器间的通信 》 html5jscss
3,386&阅读
指令与控制器之间通信,跟、也类似,也是下几种方法:
通过指令自身参数
基于event传播的方式
service的方式
通过指令自身参数来共享对象、共享方法
首先我们必须得清楚,每一个 $scope 都是scope的一个事例,而通过绑定将数据绑定在 $scope 就能实现双向绑定。scope的层次结构跟controller相关,继承关系跟又遵循了原型继承的规则,而子controller所初始化的scope是创建一个新的变量,而不是去修改父controller中的值。所以就不难使用为什么不使用基本类型变量而是使用引用类型变量去实现控制器间的通信。
指令中怎么创建 scope:
scope默认值是false,表示scope跟父controller的scope相同
scope:true,表示创建一个继承自父scope的新scope,这样就可以让同一个父控制下的指令都可以使用这个scope进行通信。
创建完全独立的属于指令自己的scope,这样可以防止读取和修改父级scope的数据。
创建完全独立的scope的API:
=:提供一个与父scope的双向绑定的属性。
&:能够在指令内访问定义在父scope注册的函数。
@:提供一个 父scope-》子指令的单向绑定的属性。
双向数据绑定。
通过 services 实现控制器与指令双向通信,也比较简单,
基于event传播的方式
使用基于event来让控制器跟指令通信,指令中的 scope 就不能设置为独立的了,所以编写指令最好不要使用此方法。
其实跟控制器通信中基于event传播原理是一样,只是把controller中的代码写在了diresctive中的controller中而已。
通过三种方法比较:个人比较推荐方法一中的创建独立scope。因为这样既不会污染其他scope,也能够一眼就能看出来该指令需要从外部scope得到方法或者属性。对于方法二个人觉得用在初始化还是挺不错的。对于方法三则不很不推荐。
本文源链接:转载请注明《》|
看过此文章的人还看过
热门标签&&.&.&.&&}

我要回帖

更多关于 angularjs 隐藏div 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信