AngularJS实践之使用NgModelController进行数据绑定
前言
在Angular应用中,ng-model指令时不可缺少的一个部分,它用来将视图绑定到数据,是双向绑定魔法中重要的一环。ngModelController则是ng-model指令中所定义的controller。这个controller包含了一些用于数据绑定,验证,CSS更新,以及数值格式化和解析的服务。它不用来进行DOM渲染或者监听DOM事件。与DOM相关的逻辑都应该包含在其他的指令中,然后让这些指令来试用ngModelController中的数据绑定功能。
注意:本篇文章不是对NgModelController文档的说明,而是更偏向实践。下面我将全程带领大家去实现一个自定义指令,并且利用ng-model属性来做双方的数据绑定。
示例
我们的app中使用了一个自定义的指令,名字叫做timeDruation
如下
<div ng-app="HelloApp" ng-controller="HelloController"> <h1>自定义指令</h1> <time-duration ng-model="test"></time-duration> <h1>默认指令</h1> <input ng-model="test">second </div>
JS代码如下,
angular.module('HelloApp', []) .directive('timeDuration', TimeDurationDirective); .controller('HelloController', function($scope) { $scope.test = 1; });
我们的示例指令可以做这样一件事,可以指定几个常见的时间单位,并且能够输入数据。最终我们将得到对应的秒数。其功能的截图如下,
这里我们特意将test变量分别绑定到我们的自定义指令和默认指令中,以观察其效果。
自定义指令
闲话少叙,下面来看代码
先上指令的模板。从上图中可以看出,指令包含一个输入框一个下拉选择框。
<div class="time-duration"> <input ng-model='num'> <select ng-model='unit'> <option value="seconds">Seconds</option> <option value="minutes">Minutes</option> <option value="hours">Hours</option> <option value="days">Days</option> </select> </div>
模板其实很简单,这里就不多说了。下面我们来看看这个指令的逻辑部分。
function TimeDurationDirective() { var tpl = '....'; // 指令模板代码就是上面的内容,这里就不复制了。 return { restrict: 'E', replace: true, template: tpl, require: 'ngModel', scope: {}, link: function(scope, element, attrs, ngModelController) { var multiplierMap = { seconds: 1, minutes: 60, hours: 3600, days: 86400 }; var multiplierTypes = ['seconds', 'minutes', 'hours', 'days']; // TODO } }; }
指令的link方法我们暂时TODO了它。后面会逐步完善。
我先来看看这个指令的定义,其中用到了require声明。简单来说,require的作用就是为这个directive声明一个依赖关系,表明此directive依赖另一个指令的controller属性。
这里稍微说明一下require的衍生用法。
我们可以在require前加上修辞量词,比如,
return { require: '^ngModel' } return { require: '?ngModel' } return { require: '?^ngModel' }
1、^前缀修饰表示允许查找当前指令的父级指令,如果找不到对应指令的controller则抛出一个错误。
2、?则表示将这个require动作变成一个可选项,意思就是找不到对应指令的controller就算了,不会抛出错误。
3、当然,我们也可以联合使用这两个前缀修饰。
相对?ngModel,^ngModel我们使用的频率要更加高一点。
比如
<my-directive ng-model="my-model"> <other-directive></other-directive> </my-directive>
这时,我们在other-directive中使用require: ^ngModel,它将会自动查找my-directive指令声明中的controller属性。
使用NgModelController
当我们声明了require: 'ngModel'之后,在link方法中会注入第四个参数,这个参数就是我们require的那个指令对应的controller。这里就是内置指令ngModel的指控器ngModeController了。
link: function (scope, element, attrs, ngModelCtrl) { // TODO }
$viewValue和$modelValue
在ngModelController中有两个很重要的属性,一个叫做$viewValue,一个叫做$modeValue。
这两者的含义官方的解释如下
$viewValue: Actual string value in the view.
$modelValue: The value in the model, that the control is bound to.
如果你对上面的官方解释有疑惑的话,我这里给出一种我个人的解释。
$viewView就是指令渲染模板所用的值,而$modelView是在控制器中流通的值。很多时候,这两个值可能是不一样的。
比如你在页面上展示了一个日期,它显示的可能是“Oct. 20 2015”这样的字符串,但是呢,这个字符串在控制器中对应的值可能是一个Javascript的Date对象的实例。
再比如,我们的这个time-duration示例中,$viewValue其实指的是指令模板中num和unit组合出来的值,而$modelValue是HelloAppController中test变量对应的值。
$formatters和$parses
除了$viewValue和$modelValue这两个属性之外,还有两个用来处理他们的方法。分别是$parses和$formatters。
前者的是作用是将$viewValue->$modelValue,后者的作用恰好相反,是将$modelValue->$viewValue。
time-duration指令与外部控制器以及其内部的运作如下图,
1、在外部控制器中(即这里的HelloApp的controller),我们通过ng-model="test"将test变量传入指令time-duration中,并建立绑定关系。
2、在指令内部,$modelValue其实就是test值的一份拷贝。
3、我们通过$formatters()方法将$modelValue转变成$viewValue。
4、然后调用$render()方法将$viewValue渲染到directive template中。
5、当我们通过某种途径监控到指令模板中的变量发生变化之后,我们调用$setViewValue()来更新$viewValue。
6、与(4)相对应,我们通过$parsers方法将$viewValue转化成$modelValue。
7、当$modelValue发生变化后,则会去更新HelloApp的UI。
完善指令逻辑
按照上面的流程,我们先来将$modelValue转化成$viewValue,然后在指令模板中进行渲染。
// $formatters接受一个数组 // 数组是一系列方法,用于将modelValue转化成viewValue ngModelController.$formatters.push(function(modelValue) { var unit = 'minutes', num = 0, i, unitName; modelValue = parseInt(modelValue || 0); for (i = multiplierTypes.length-1; i >= 0; i--) { unitName = multiplierTypes[i]; if (modelValue % multiplierMap[unitName] === 0) { unit = unitName; break; } } if (modelValue) { num = modelValue / multiplierMap[unit]; } return { unit: unit, num: num }; });
最后返回的对象就是$viewValue的value。(当然$viewValue还会有其他的一些属性。)
第二步,我们调用$render方法将$viewValue渲染到指令模板中去。
// $render用于将viewValue渲染到指令的模板中 ngModelController.$render = function() { scope.unit = ngModelCtrl.$viewValue.unit; scope.num = ngModelCtrl.$viewValue.num; };
第三步,我们通过$watch来监控指令模板中num和unit变量。当其发生变化时,我们需要更新$viewValue。
scope.$watch('unit + num', function() { // $setViewValue用于更新viewValue ngModelController.$setViewValue({ unit: scope.unit, num: scope.num }); });
第四步,我们通过$parsers将$viewValue->$modelValue。
// $parsers接受一个数组 // 数组是一系列方法,用于将viewValue转化成modelValue ngModelController.$parsers.push(function(viewValue) { var unit = viewValue.unit; var num = viewValue.num; var multiplier; multiplier = multiplierMap[unit]; return num * multiplier; });
更多AngularJS实践之使用NgModelController进行数据绑定相关文章请关注PHP中文网!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

JavaScript字符串替换方法详解及常见问题解答 本文将探讨两种在JavaScript中替换字符串字符的方法:在JavaScript代码内部替换和在网页HTML内部替换。 在JavaScript代码内部替换字符串 最直接的方法是使用replace()方法: str = str.replace("find","replace"); 该方法仅替换第一个匹配项。要替换所有匹配项,需使用正则表达式并添加全局标志g: str = str.replace(/fi

因此,在这里,您准备好了解所有称为Ajax的东西。但是,到底是什么? AJAX一词是指用于创建动态,交互式Web内容的一系列宽松的技术。 Ajax一词,最初由Jesse J创造

10款趣味横生的jQuery游戏插件,让您的网站更具吸引力,提升用户粘性!虽然Flash仍然是开发休闲网页游戏的最佳软件,但jQuery也能创造出令人惊喜的效果,虽然无法与纯动作Flash游戏媲美,但在某些情况下,您也能在浏览器中获得意想不到的乐趣。 jQuery井字棋游戏 游戏编程的“Hello world”,现在有了jQuery版本。 源码 jQuery疯狂填词游戏 这是一个填空游戏,由于不知道单词的上下文,可能会产生一些古怪的结果。 源码 jQuery扫雷游戏

本教程演示了如何使用jQuery创建迷人的视差背景效果。 我们将构建一个带有分层图像的标题横幅,从而创造出令人惊叹的视觉深度。 更新的插件可与JQuery 1.6.4及更高版本一起使用。 下载

本文讨论了在浏览器中优化JavaScript性能的策略,重点是减少执行时间并最大程度地减少对页面负载速度的影响。

本文演示了如何使用jQuery和ajax自动每5秒自动刷新DIV的内容。 该示例从RSS提要中获取并显示了最新的博客文章以及最后的刷新时间戳。 加载图像是选择

Matter.js是一个用JavaScript编写的2D刚体物理引擎。此库可以帮助您轻松地在浏览器中模拟2D物理。它提供了许多功能,例如创建刚体并为其分配质量、面积或密度等物理属性的能力。您还可以模拟不同类型的碰撞和力,例如重力摩擦力。 Matter.js支持所有主流浏览器。此外,它也适用于移动设备,因为它可以检测触摸并具有响应能力。所有这些功能都使其值得您投入时间学习如何使用该引擎,因为这样您就可以轻松创建基于物理的2D游戏或模拟。在本教程中,我将介绍此库的基础知识,包括其安装和用法,并提供一
