GVKun编程网logo

实例剖析AngularJS框架中数据的双向绑定运用(angularjs 双向绑定原理)

35

在本文中,我们将给您介绍关于实例剖析AngularJS框架中数据的双向绑定运用的详细内容,并且为您解答angularjs双向绑定原理的相关问题,此外,我们还将为您提供关于AngularJS数据的双向绑

在本文中,我们将给您介绍关于实例剖析AngularJS框架中数据的双向绑定运用的详细内容,并且为您解答angularjs 双向绑定原理的相关问题,此外,我们还将为您提供关于Angular JS数据的双向绑定详解及实例、Angular.js 应用的双向绑定、AngularJS _AngularJs 双向绑定原理(数据绑定机制)、angularjs – Angular,两个变量的双向绑定的知识。

本文目录一览:

实例剖析AngularJS框架中数据的双向绑定运用(angularjs 双向绑定原理)

实例剖析AngularJS框架中数据的双向绑定运用(angularjs 双向绑定原理)

数据绑定

通过把一个文本输入框绑定到person.name属性上,就能把我们的应用变得更有趣一点。这一步建立起了文本输入框跟页面的双向绑定。

在这个语境里“双向”意味着如果view改变了属性值,model就会“看到”这个改变,而如果model改变了属性值,view也同样会“看到”这个改变。Angular.js 为你自动搭建好了这个机制。如果你好奇这具体是怎么实现的,请看我们之后推出的一篇文章,其中深入讨论了digest_loop 的运作。

要建立这个绑定,我们在文本输入框上使用ng-model 指令属性,像这样:

rush:js;">
Hello {{ person.name }}

现在我们建立好了一个数据绑定(没错,就这么容易),来看看view怎么改变model吧:

试试看:

当你在文本框里输入时,下面的名字也自动随之改变,这就展现了我们数据绑定的一个方向:从view到model。

我们也可以在我们的(客户端)后台改变model,看这个改变自动在前端体现出来。要展示这一过程,让我们在 MyController 的model里写一个计时器函数, 更新 $scope 上的一个数据。下面的代码里,我们就来创建这个计时器函数,它会在每秒计时(像钟表那样),并更新 $scope 上的clock变量数据:

rush:js;"> app.controller('MyController',function($scope) { $scope.person = { name: "Ari Lerner" }; var updateClock = function() { $scope.clock = new Date(); }; var timer = setInterval(function() { $scope.$apply(updateClock); },1000); updateClock(); });

可以看到,当我们改变model中clock变量的数据,view会自动更新来反映此变化。用大括号我们就可以很简单地让clock变量的值显示在view里:

rush:js;">
{{ clock }}

互动

前面我们把数据绑定在了文本输入框上。请注意, 数据绑定并非只限于数据,我们还可以利用绑定调用 $scope 中的函数(这一点之前已经提到过)。

对按钮、链接或任何其他的DOM元素,我们都可以用另一个指令属性来实现绑定:ng-click 。这个 ng-click 指令将DOM元素的鼠标点击事件(即 mousedown 浏览器事件)绑定到一个方法上,当浏览器在该DOM元素上鼠标触发点击事件时,此被绑定的方法就被调用。跟上一个例子相似,这个绑定的代码如下:

rush:js;">
The simplest adding machine ever

不论是按钮还是链接都会被绑定到包含它们的DOM元素的controller所有的 $scope 对象上,当它们被鼠标点击,Angular就会调用相应的方法。注意当我们告诉Angular要调用什么方法时,我们将方法名写进带引号的字符串里。

rush:js;"> app.controller('DemoController',function($scope) { $scope.counter = 0; $scope.add = function(amount) { $scope.counter += amount; }; $scope.subtract = function(amount) { $scope.counter -= amount; }; });

请看:

$scope.$watch

rush:js;"> $scope.$watch( watchExp,listener,objectEquality );

为了监视一个变量的变化,你可以使用$scope.$watch函数。这个函数有三个参数,它指明了”要观察什么”(watchExp),”在变化时要发生什么”(listener),以及你要监视的是一个变量还是一个对象。当我们在检查一个参数时,我们可以忽略第三个参数。例如下面的例子:

rush:js;"> $scope.name = 'Ryan';

$scope.$watch( function( ) {
return $scope.name;
},function( newValue,oldValue ) {
console.log('$scope.name was updated!');
} );

AngularJS将会在$scope中注册你的监视函数。你可以在控制台中输出$scope来查看$scope中的注册项目。

你可以在控制台中看到$scope.name已经发生了变化 – 这是因为$scope.name之前的值似乎undefined而现在我们将它赋值为Ryan!

对于$wach的第一个参数,你也可以使用一个字符串。这和提供一个函数完全一样。在AngularJS的源代码中可以看到,如果你使用了一个字符串,将会运行下面的代码:

rush:js;"> if (typeof watchExp == 'string' && get.constant) { var originalFn = watcher.fn; watcher.fn = function(newVal,oldVal,scope) { originalFn.call(this,newVal,scope); arrayRemove(array,watcher); }; }

这将会把我们的watchExp设置为一个函数,它也自动返回作用域中我们已经制定了名字的变量。

$$watchers

$scope中的$$watchers变量保存着我们定义的所有的监视器。如果你在控制台中查看$$watchers,你会发现它是一个对象数组。

rush:js;"> $$watchers = [ { eq: false,// 表明我们是否需要检查对象级别的相等 fn: function( newValue,oldValue ) {},// 这是我们提供的监听器函数 last: 'Ryan',// 变量的最新值 exp: function(){},// 我们提供的watchExp函数 get: function(){} // Angular's编译后的watchExp函数 } ];

$watch函数将会返回一个deregisterWatch函数。这意味着如果我们使用$scope.$watch对一个变量进行监视,我们也可以在以后通过调用某个函数来停止监视。

$scope.$apply

当一个控制器/指令/等等东西在AngularJS中运行时,AngularJS内部会运行一个叫做$scope.$apply的函数。这个$apply函数会接收一个函数作为参数并运行它,在这之后才会在rootScope上运行$digest函数。

AngularJS的$apply函数代码如下所示:

rush:js;"> $apply: function(expr) { try { beginPhase('$apply'); return this.$eval(expr); } catch (e) { $exceptionHandler(e); } finally { clearPhase(); try { $rootScope.$digest(); } catch (e) { $exceptionHandler(e); throw e; } } }

上面代码中的expr参数就是你在调用$scope.$apply()时传递的参数 – 但是大多数时候你可能都不会去使用$apply这个函数,要用的时候记得给它传递一个参数。

下面我们来看看ng-keydown是怎么来使用$scope.$apply的。为了注册这个指令,AngularJS会使用下面的代码。

rush:js;"> var ngEventDirectives = {}; forEach( 'click dblclick mousedown mouseup mouSEOver mouSEOut mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),function(name) { var directiveName = directivenormalize('ng-' + name); ngEventDirectives[directiveName] = ['$parse',function($parse) { return { compile: function($element,attr) { var fn = $parse(attr[directiveName]); return function ngEventHandler(scope,element) { element.on(lowercase(name),function(event) { scope.$apply(function() { fn(scope,{$event:event}); }); }); }; } }; }]; } );

上面的代码做的事情是循环了不同的类型的事件,这些事件在之后可能会被触发并创建一个叫做ng-[某个事件]的新指令。在指令的compile函数中,它在元素上注册了一个事件处理器,它和指令的名字一一对应。当事件被出发时,AngularJS就会运行scope.$apply函数,并让它运行一个函数。

只是单向数据绑定吗? 上面所说的ng-keydown只能够改变和元素值相关联的$scope中的值 – 这只是单项数据绑定。这也是这个指令叫做ng-keydown的原因,只有在keydown事件被触发时,能够给与我们一个新值。

但是我们想要的是双向数据绑定! 我们现在来看一看ng-model。当你在使用ng-model时,你可以使用双向数据绑定 – 这正是我们想要的。AngularJS使用$scope.$watch(视图到模型)以及$scope.$apply(模型到视图)来实现这个功能。

ng-model会把事件处理指令(例如keydown)绑定到我们运用的输入元素上 – 这就是$scope.$apply被调用的地方!而$scope.$watch是在指令的控制器中被调用的。你可以在下面代码中看到这一点:

rush:js;"> $scope.$watch(function ngModelWatch() { var value = ngModelGet($scope);

//如果作用域模型值和ngModel值没有同步
if (ctrl.$modelValue !== value) {

var formatters = ctrl.$formatters,idx = formatters.length;

ctrl.$modelValue = value;
while(idx--) {
  value = formatters[idx](value);
}

if (ctrl.$viewValue !== value) {
  ctrl.$viewValue = value;
  ctrl.<a href="https://www.jb51.cc/tag/render/" target="_blank">$render</a>();
}

}

return value;
});

如果你在调用$scope.$watch时只为它传递了一个参数,无论作用域中的什么东西发生了变化,这个函数都会被调用。在ng-model中,这个函数被用来检查模型和视图有没有同步,如果没有同步,它将会使用新值来更新模型数据。这个函数会返回一个新值,当它在$digest函数中运行时,我们就会知道这个值是什么!

为什么我们的监听器没有被触发?

如果我们在$scope.$watch的监听器函数中停止这个监听,即使我们更新了$scope.name,该监听器也不会被触发。

正如前面所提到的,AngularJS将会在每一个指令的控制器函数中运行$scope.$apply。如果我们查看$scope.$apply函数的代码,我们会发现它只会在控制器函数已经开始被调用之后才会运行$digest函数 – 这意味着如果我们马上停止监听,$scope.$watch函数甚至都不会被调用!但是它究竟是怎样运行的呢?

$digest函数将会在$rootScope中被$scope.$apply所调用。它将会在$rootScope中运行digest循环,然后向下遍历每一个作用域并在每个作用域上运行循环。在简单的情形中,digest循环将会触发所有位于$$watchers变量中的所有watchExp函数,将它们和最新的值进行对比,如果值不相同,就会触发监听器。

当digest循环运行时,它将会遍历所有的监听器然后再次循环,只要这次循环发现了”脏值”,循环就会继续下去。如果watchExp的值和最新的值不相同,那么这次循环就会被认为发现了脏值。理想情况下它会运行一次,如果它运行超10次,你会看到一个错误。

因此当$scope.$apply运行的时候,$digest也会运行,它将会循环遍历$$watchers,只要发现watchExp和最新的值不相等,变化触发事件监听器。在AngularJS中,只要一个模型的值可能发生变化,$scope.$apply就会运行。这就是为什么当你在AngularJS之外更新$scope时,例如在一个setTimeout函数中,你需要手动去运行$scope.$apply():这能够让AngularJS意识到它的作用域发生了变化。

创建自己的脏值检查

到此为止,我们已经可以来创建一个小巧的,简化版本的脏值检查了。当然,相比较之下,AngularJS中实现的脏值检查要更加先进一些,它提供疯了异步队列以及其他一些高级功能。

设置Scope

Scope仅仅只是一个函数,它其中包含任何我们想要存储的对象。我们可以扩展这个函数的原型对象来复制$digest和$watch。我们不需要$apply方法,因为我们不需要在作用域的上下文中执行任何函数 – 我们只需要简单的使用$digest。我们的Scope的代码如下所示:

rush:js;"> var Scope = function( ) { this.$$watchers = []; };

Scope.prototype.$watch = function( ) {

};

Scope.prototype.$digest = function( ) {

};

我们的$watch函数需要接受两个参数,watchExp和listener。当$watch被调用时,我们需要将它们push进入到Scope的$$watcher数组中。

rush:js;"> var Scope = function( ) { this.$$watchers = []; };

Scope.prototype.$watch = function( watchExp,listener ) {
this.$$watchers.push( {
watchExp: watchExp,listener: listener || function() {}
} );
};

Scope.prototype.$digest = function( ) {

};

你可能已经注意到了,如果没有提供listener,我们会将listener设置为一个空函数 – 这样一来我们可以$watch所有的变量。

接下来我们将会创建$digest。我们需要来检查旧值是否等于新的值,如果二者不相等,监听器就会被触发。我们会一直循环这个过程,直到二者相等。这就是”脏值”的来源 – 脏值意味着新的值和旧的值不相等!

rush:js;"> var Scope = function( ) { this.$$watchers = []; };

Scope.prototype.$watch = function( watchExp,listener: listener || function() {}
} );
};

Scope.prototype.$digest = function( ) {
var dirty;

do {
dirty = false;

  for( var i = 0; i < this.$$watchers.length; i++ ) {
    var newValue = this.$$watchers[i].watchExp(),oldValue = this.$$watchers[i].last;

    if( oldValue !== newValue ) {
      this.$$watchers[i].listener(newValue,oldValue);

      dirty = true;

      this.$$watchers[i].last = newValue;
    }
  }

} while(dirty);
};

接下来,我们将创建一个作用域的实例。我们将这个实例赋值给$scope。我们接着会注册一个监听函数,在更新$scope之后运行$digest!

rush:js;"> var Scope = function( ) { this.$$watchers = []; };

Scope.prototype.$watch = function( watchExp,oldValue);

      dirty = true;

      this.$$watchers[i].last = newValue;
    }
  }

} while(dirty);
};

var $scope = new Scope();

$scope.name = 'Ryan';

$scope.$watch(function(){
return $scope.name;
},oldValue ) {
console.log(newValue,oldValue);
} );

$scope.$digest();

成功了!我们现在已经实现了脏值检查(虽然这是最简单的形式)!上述代码将会在控制台中输出下面的内容:

rush:plain;"> Ryan undefined

这正是我们想要的结果 – $scope.name之前的值是undefined,而现在的值是Ryan。

现在我们把$digest函数绑定到一个input元素的keyup事件上。这就意味着我们不需要自己去调用$digest。这也意味着我们现在可以实现双向数据绑定!

rush:js;"> var Scope = function( ) { this.$$watchers = []; };

Scope.prototype.$watch = function( watchExp,oldValue);

      dirty = true;

      this.$$watchers[i].last = newValue;
    }
  }

} while(dirty);
};

var $scope = new Scope();

$scope.name = 'Ryan';

var element = document.querySelectorAll('input');

element[0].onkeyup = function() {
$scope.name = element[0].value;

$scope.$digest();
};

$scope.$watch(function(){
return $scope.name;
},oldValue ) {
console.log('Input value updated - it is Now ' + newValue);

element[0].value = $scope.name;
} );

var updateScopeValue = function updateScopeValue( ) {
$scope.name = 'Bob';
$scope.$digest();
};

使用上面的代码,无论何时我们改变了input的值,$scope中的name属性都会相应的发生变化。这就是隐藏在AngularJS神秘外衣之下数据双向绑定的秘密!

Angular JS数据的双向绑定详解及实例

Angular JS数据的双向绑定详解及实例

Angular JS数据的双向绑定

接触AngularJS许了,时常问自己一些问题,如果是我实现它,会在哪些方面选择跟它相同的道路,哪些方面不同。为此,记录了一些思考,给自己回顾,也供他人参考。

初步大致有以下几个方面:

  • 数据双向绑定
  • 视图模型的继承关系
  • 模块和依赖注入的设计
  • 待定

数据的双向绑定

Angular实现了双向绑定机制。所谓的双向绑定,无非是从界面的操作能实时反映到数据,数据的变更能实时展现到界面。

一个最简单的示例就是这样:

rush:js;">
function CounterCtrl($scope) { $scope.counter = 1; }

这个例子很简单,毫无特别之处,每当点击一次按钮,界面上的数字就增加一。

绑定数据是怎样生效的

初学AngularJS的人可能会踩到这样的坑,假设有一个指令:

rush:js;"> var app = angular.module("test",[]);

app.directive("myclick",function() {
return function (scope,element,attr) {
element.on("click",function() {
scope.counter++;
});
};
});

app.controller("CounterCtrl",function($scope) {
$scope.counter = 0;
});
<body ng-app="test">
<div ng-controller="CounterCtrl">

Angular.js 应用的双向绑定

Angular.js 应用的双向绑定

效果:

源代码:

<html ng-app>
  <head>
    <meta charset="utf-8">
    <title>Angular.js Example</title>
    <script src="angular/angular.js"></script>
    <script>
      function NameCtrl($scope){
        $scope.firstName = ''John'';
        $scope.lastName = ''Smith'';
      }
    </script>
  </head>
  <body ng-controller="NameCtrl">
    First name:<input ng-model="firstName" type="text"/>
    <br>
    Last name:<input ng-model="lastName" type="text"/>
    <br>
    Hello {{firstName}} {{lastName}}
  </body>
</html>

这段代码是一个非常基础的 AngularJS 示例,展示了如何使用 AngularJS 创建一个简单的交互式用户界面。在这个例子中,我们定义了一个简单的控制器 NameCtrl,它管理一个表单,表单中包含用户的 firstNamelastName。随着用户输入的变化,页面上相应的部分也会实时更新以反映这些变化。下面将详细分析这段代码的每个部分:

HTML 结构

<html ng-app>
  <head>
    <meta charset="utf-8">
    <title>Angular.js Example</title>
    <script src="angular/angular.js"></script>

这段代码首先定义了 HTML 文档的基本结构,包括 headbody<html ng-app> 表示整个 HTML 页面是一个 AngularJS 应用的根元素。ng-app 指令是用来标记 AngularJS 应用的启动点,它告诉 AngularJS 从这里开始编译和执行代码。

head 部分,除了设置字符集和页面标题外,最重要的是通过 <script src="angular/angular.js"></script> 引入了 AngularJS 的库文件。这是使用 AngularJS 开发的前提,因为所有的功能都需要通过这个库来实现。

JavaScript 控制器

<script>
  function NameCtrl($scope){
    $scope.firstName = ''John'';
    $scope.lastName = ''Smith'';
  }
</script>

这段 <script> 定义了一个名为 NameCtrl 的控制器。在 AngularJS 中,控制器是用来定义应用的业务逻辑的地方。这里 NameCtrl 控制器接受一个 $scope 对象作为参数,$scope 是一个特殊的对象,用于双向绑定数据和视图。控制器内部设置了 $scope.firstName$scope.lastName,初始化为 JohnSmith。这两个属性存储的值将用于数据绑定,展示在视图中,并且能够响应视图上的数据变化。

视图和数据绑定

<body ng-controller="NameCtrl">
  First name: <input ng-model="firstName" type="text" />
  <br>
  Last name: <input ng-model="lastName" type="text" />
  <br>
  Hello `{{firstName}} {{lastName}}`
</body>
</html>

body 标签中,我们使用 ng-controller="NameCtrl" 将此部分的视图与 NameCtrl 控制器关联起来。这意味着在这部分的 HTML 中可以使用控制器定义的 $scope 上的属性和方法。

<input ng-model="firstName" type="text" /><input ng-model="lastName" type="text" /> 使用 ng-model 指令绑定到 $scope 上的 firstNamelastName 属性。这种绑定是双向的:视图(input 输入框)上的任何变化都会实时更新到 $scope 的属性上,反之亦然。

Hello {{firstName}} {{lastName}}` 则是 AngularJS 的插值表达式。这里,它将 firstNamelastName 的当前值插入到 HTML 中,实现了数据的实时显示。当 input 中的值发生改变时,由于 $scope` 属性的双向绑定,插值表达式中的内容也会立即更新。

总结

这个示例展示了 AngularJS 的一些核心特性:模块化控制器、数据绑定、指令以及表达式。通过这些特性,开发者可以快速构建动态交互的网页应用。AngularJS 通过其数据绑定和依赖注入的特点,使得开发复杂的单页应用(SPA)变得更加高效和简单。在实际应用中,这种模式可以扩

展到更复杂的业务逻辑和更多的数据处理,展示出 AngularJS 强大的开发能力。

AngularJS _AngularJs 双向绑定原理(数据绑定机制)

AngularJS _AngularJs 双向绑定原理(数据绑定机制)

原文地址:

https://www.jianshu.com/p/ad0c48810bf1

 

AngularJsscope 模型上设置了一个 监听队列,用来监听数据变化并更新 view 。每次绑定一个东西到 view(html) 上时 AngularJs 就会往 $watch 队列里插入一条 $watch,用来检测它监视的 model 里是否有变化的东西。当浏览器接收到可以被 angular context 处理的事件时,$digest 循环就会触发。$digest 会遍历所有的 $watch。从而更新DOM

$watch

这有点类似于我们的观察者模式,在当前作用域$scope下,我们创建一个监控器$watchers和一个监听器$watch$watchers 负责管理所有的 $watch,当我们每次绑定到UI上的时候就自动创建一个$watch,并把它放到 $watchers

controller.js

  1. app.controller('MainCtrl', function($scope) {
  2. $scope.Hello = "Hello";
  3. $scope.world = "World";
  4. });

index.html

  1. <div>{{Hello}}</div>

这里,即便我们在$scope上添加了两个变量,但是只有一个绑定在了UI上,因此在这里只生成了一个$watch

$digest

当浏览器接收到可以被angular context处理的事件时,$digest循环就会触发。$digest将会遍历我们的$watch,如果$watch没有变化,这个循环检测就将停止,如果有至少一个更新过,这个循环就会再次触发,直到所有的$watch都没有变化。这样就能够保证每个model都已经不会再变化。这就是脏检查(Dirty Checking)机制

controller.js

  1. app.controller('MainCtrl', function() {
  2. $scope.name = "Foo";
  3. $scope.changeFoo = function() {
  4. $scope.name = "Bar";
  5. }
  6. });

index.js

  1. <div>{{ name }}</div>
  2. <button ng-click="changeFoo()">Change the name</button>
  • 当我们按下按钮
  • 浏览器接收到一个事件,进入angular context
  • $digest循环开始执行,查询每个$watch是否变化。
  • 由于监视$scope.name$watch报告了变化,它会强制再执行一次$digest循环。
  • 新的$digest循环没有检测到变化。
  • 更新与$scope.name新值相应部分的DOM

$apply

$apply 我们可以直接理解为刷新UI。如果当事件触发时,你调用$apply,它会进入angular context,如果没有调用就不会进入,之后的$digest检测机制就不会触发

  1. app.directive('clickable', function() {
  2. return {
  3. restrict: "E",
  4. scope: {
  5. foo: '='
  6. },
  7. template: '<ul><li>{{foo}}</li></ul>',
  8. link: function(scope, element, attrs) {
  9. element.bind('click', function() {
  10. scope.foo++;
  11. console.log(scope.foo);
  12. });
  13. }
  14. }
  15. });

当我们调用clickable指令的时候,我们可以看到foo的值增加了,但是界面上显示的内容并没有改变。$digest脏检测机制没有触发,检测foo$watch就没有执行。

$apply()方法的两种形式

1) 无参

$scope.$apply();

 

  1. element.bind('click', function() {
  2. scope.foo++;
  3. //if error
  4. scope.$apply();
  5. });

当我们使用这种形式的时候,如果在scope.$apply之前程序发生异常,那scope.$apply没有执行,界面就不会更新

2) 有参

  1. $scope.$apply(function(){
  2. ...
  3. })

 

  1. element.bind('click', function() {
  2. scope.$apply(function() {
  3. scope.foo++;
  4. });
  5. })

如果用这种形式,即使后面的发生异常,数据还是会更新。

在 AngularJS 中使用 $watch

常用的使用方式:

  1. $scope.name = 'Hello';
  2. $scope.$watch('name', function(newValue, oldValue) {
  3. if (newValue === oldValue) { return; }
  4. $scope.updated++;
  5. });

传入到$watch()中的第二个参数是一个回调函数,该函数在name的值发生变化的时候会被调用。

如果要监听的是一个对象,那还需要第三个参数:

  1. $scope.data.name = 'Hello';
  2. $scope.$watch('data', function(newValue, oldValue) {
  3. if (newValue === oldValue) { return; }
  4. $scope.updated++;
  5. }, true);

表示比较的是对象的值而不是引用,如果不加第三个参数true,在 data.name 变化时,不会触发相应操作,因为引用的是同一引用。

总结

1) 只有在$scope变量绑定到页面上,才会创建 $watch

2) $apply决定事件是否可以进入angular context

3) $digest 循环检查model时最少两次,最多10次(多于10次抛出异常,防止无限检查)

4) AngularJs自带的指令已经实现了$apply,所以不需要我们额外的编写

5) 在自定义指令时,建议使用带function参数的$apply



作者:Nickyzhang
链接:https://www.jianshu.com/p/ad0c48810bf1
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

angularjs – Angular,两个变量的双向绑定

angularjs – Angular,两个变量的双向绑定

我有两个与函数相关的变量,用户应该能够在输入字段中更改其中一个或另一个应该自动更改另一个的输入字段.

我怎么能这样做,现在我只是使用$watch.

这是一些示例代码和一个fiddle.

JS,

angular.module("test",[])
.controller("MyController",function ($scope) {
    $scope.letter = 'A';
    $scope.number = 1;
    $scope.map = { 'A': 1,'B': 2,'C': 3,'D': 4 };

    $scope.$watch('letter',function(new_val,old_val){
        if(new_val != old_val){
            $scope.number = $scope.map[new_val];
        }
    });
    $scope.$watch('number',old_val){
        ...
    });
});

HTML,

<div ng-app="test">
    <div ng-controller="MyController">
        <input ng-model="letter" />
        <input type="number" ng-model="number" />
    </div>
</div>

解决方法

有很多方法可以做到这一点,使用$watch肯定是其中之一.正如Matt所提到的,您还可以使用ng-change指令在控制器上触发方法.

我想提供的第三种方法是使用ES5 properties和Angular在1.2中引入的Controller ‘as’ syntax

如果将控制器定义为JS对象而不是使用匿名函数,则可以向原型添加属性和方法:

myController = function () {
    this.map = {'A': 1,'D': 4};
    this._letter = 'A';
    this._number = 1;
};

现在我们可以提取您已经完成的工作,将您的字母和数字值转换为函数:

myController.prototype.getLetterValue = function (num) {
    for (var key in this.map) {
        if (this.map.hasOwnProperty(key)) {
            if (this.map[key] === num) {
                return key;
            }
        }
    }
};

myController.prototype.getNumberValue = function (letter) {
    return this.map[letter];
};

最后,我们将在您的控制器上声明一些使用Object.defineProperty封装所需功能的属性.

Object.defineProperty(
myController.prototype,"letter",{
    get: function () {
        return this._letter;
    },set: function (newValue) {
        this._letter = newValue;
        this._number = this.getNumberValue(this._letter);
    },enumerable: true,configurable: true
});

Object.defineProperty(
myController.prototype,"number",{
    get: function () {
        return this._number;
    },set: function (newValue) {
        this._number = newValue;
        this._letter = this.getLetterValue(this._number);
    },configurable: true
});

将此控制器添加到您的模块:

angular.module("test",[])
    .controller("MyController",myController);

最后,您只需稍微修改绑定语法,以便将新的Controller’用作’语法.这将允许您直接绑定到控制器上的属性和方法,而不必使用$scope

<div ng-app="test">
    <div ng-controller="MyController as ctrl">
        <input ng-model="ctrl.letter" />
        <input type="number" ng-model="ctrl.number" />
    </div>
</div>

Live Demo

摘要

这不是完全没有代码,但确实有几个优点.

>您的控制器与$scope和$watch脱钩,使其更具便携性>控制器代码更易于阅读,因为所有功能都没有嵌套在匿名函数中>代码更具前瞻性,因为Angular的未来版本可能会通过使用本机observable来完全消除$scope和$digest循环.

今天关于实例剖析AngularJS框架中数据的双向绑定运用angularjs 双向绑定原理的分享就到这里,希望大家有所收获,若想了解更多关于Angular JS数据的双向绑定详解及实例、Angular.js 应用的双向绑定、AngularJS _AngularJs 双向绑定原理(数据绑定机制)、angularjs – Angular,两个变量的双向绑定等相关知识,可以在本站进行查询。

本文标签: