angularjs 1.3 综合学习 (one way bind , ng-if , ng-switch , ng-messages, ng-form ,ng-model )

时间:2023-03-09 15:15:15
angularjs 1.3 综合学习 (one way bind , ng-if , ng-switch , ng-messages, ng-form ,ng-model )

主要讲解1.3后的一些新功能,和一些以前没有介绍的小功能 (ng-if,ng-switch).

1.one way bind

 这个之前的版本已经有人自己实现了,但是在1.3之后,angularjs 有自带的了。用法极其简单 .

<div ng-app="app" ng-controller="ctrl">
{{ ::value }}
</div>
<script src="../../js/Stooges.js"></script>
<script src="../../js/ng-1.3.10/angular.js"></script>
<script>
var app = angular.module("app", []);
app.controller("ctrl", ["$scope", "$timeout", function ($scope, $timeout) {
$scope.value = "keatkeat";
$timeout(function () {
$scope.value = "xinyao";
},2000);
}]);
</script>

看到吗 ?只是把从前的 {{ value }} 改成 {{ ::value }} . 加了 :: 就表示这个值只是要单向绑定,之后$scope改变了也不会在同步到模板了。

2.ng-if

 ng-if 是用来做动态模板的,如果你的模板有一部分内容是依据某些数据来决定的就可以用啦。

他和ng-hide主要区别在,ng-if 如果是false 的情况它不会生成dom,这有时对性能是好的。

ng-if 为true时,angularjs 会使用之前clone好的模板,然后compile了append出去。

<div ng-app="app" ng-controller="ctrl">
<div ng-if="isTrue">
ok
</div>
<div ng-if="!isTrue">
no
</div>
</div>
<script src="../../js/Stooges.js"></script>
<script src="../../js/ng-1.3.10/angular.js"></script>
<script>
var app = angular.module("app", []);
app.controller("ctrl", ["$scope", "$timeout", function ($scope, $timeout) {
$scope.isTrue = false;
$timeout(function () {
$scope.isTrue = true;
}, 2000);
}]);
</script>

angularjs 没有 else 指令(不过有人自己实现了) , 不过我们可以用上面的写法来模拟 else

ng-if 会自动创建新的继承 scope . 在有ng-model 的情况下多留意,有坑.

<div ng-app="app" ng-controller="ctrl">
<div ng-form="form">
parent value : {{value}}
<br />
model value :{{ form.age.$modelValue }}
<div ng-if="isTrue">
<input type="text" name="age" ng-model="value" />
<br />
child value : {{value}}
</div>
</div>
</div>
<script src="../../js/Stooges.js"></script>
<script src="../../js/ng-1.3.10/angular.js"></script>
<script>
var app = angular.module("app", []);
app.controller("ctrl", ["$scope", "$timeout", function ($scope, $timeout) {
$scope.isTrue = true;
$scope.value = "keatkeat";
}]);
</script>

当我们输入 text 的时候 , $modelValue 和 child value 都会更新,但是 parent value 却不会了。这是正确的原型概念 (http://www.cnblogs.com/keatkeat/p/3983952.html)

一般情况我们在做form 时, 通常我们设计一个对象用于装所有的 value ,这样就不必担心 继承scope引起的问题了 .

稍微改一下就可以了.

<div ng-app="app" ng-controller="ctrl">
<div ng-form="form">
parent value : {{value.age}}
<br />
model value :{{ form.age.$modelValue }}
<div ng-if="isTrue">
<input type="text" name="age" ng-model="value.age" />
<br />
child value : {{value.age}}
</div>
</div>
</div>
<script src="../../js/Stooges.js"></script>
<script src="../../js/ng-1.3.10/angular.js"></script>
<script>
var app = angular.module("app", []);
app.controller("ctrl", ["$scope", "$timeout", function ($scope, $timeout) {
$scope.isTrue = true;
$scope.value = { age : 13 }; //换成对象
}]);
</script>

3.ng-switch

这个和 ng-if 差不多,和一般js switch 一样的概念 . 它也是会创建继承scope哦.

    <div ng-app="app" ng-controller="ctrl">
<div ng-switch="switchCase">
<div ng-switch-when="case1">case2</div><!--case1 必须是一个 string, 不可以是表达式 , (case1 != $scope.case1)-->
<div ng-switch-when="case2">case2</div>
<div ng-switch-default>default case</div>
</div>
</div>
<script src="../../js/Stooges.js"></script>
<script src="../../js/ng-1.3.10/angular.js"></script>
<script>
var app = angular.module("app", []);
app.controller("ctrl", ["$scope", "$timeout", function ($scope, $timeout) {
$scope.switchCase = "case2";
$timeout(function () {
$scope.switchCase = "case1";
}, 2000);
}]);
</script>

4. ng-messages

这个主要用于form 验证错误时的error message.

<div ng-app="app" ng-controller="ctrl">
<form novalidate>
<div ng-form="form">
<input type="email" ng-minlength="2" required name="email" ng-model="formData.email" />
<div ng-messages="form.email.$error" ng-messages-multiple>
<div ng-message="required">must fill in email</div>
<div ng-message="email">no a email format</div>
<div ng-message="minlength">at least 2 words</div>
</div>
</div>
</form>
</div>
<script src="../../js/Stooges.js"></script>
<script src="../../js/ng-1.3.10/angular.js"></script>
<script src="../../js/ng-1.3.10/angular-messages.js"></script>
<script>
var app = angular.module("app", ['ngMessages']);
app.controller("ctrl", ["$scope", "$timeout", function ($scope, $timeout) {
$scope.formData = {};
}]);
</script>

注意这是一个而且的模块必须加载 ['ngMessages'] 和引入文件 angular-messages.js

上面是一个能匹配多个错误信息的例子. 当错误出现时,特定的div就会被显示出来了。form.email.$error 是一个这样的对象 :  { "email": true, "minlength": true } , true 表示验证失败了.

5. ng-model and ng-form

这2个我之前写过一篇了 http://www.cnblogs.com/keatkeat/p/3912530.html

当时还在1.3 beta , 现在我会把一些常用到的在讲解一篇.还有一些新新特性也一起说说。

首先要强调,如果你想把表单做好,做的很 "angular way" 的话, ng-form , ng-model , 自定义指令, 验证, 都必须很清楚。你把它们连在一起才能强大。

5.1 ngModel.$formatters 和 ngModel.$parsers

这2个东西是 ng-model 在同步数据的时候的 pipeline , ngModel 有2个主要属性 ($viewValue , $modelValue)

顾名思义啦, 这2个值通常是一样的。但是有时候我们希望他们不一样,比如日期格式。在 $modelValue 是 datetime , 在 $viewValue 是 string .

这时我们就可以通过拦截 pipeline , 做一些convertion 了.

<div ng-app="app" ng-controller="ctrl">
<form novalidate autocomplete="off">
<div ng-form="form">
model value : {{ form.name.$modelValue }} , Type : {{ getType(form.name.$modelValue) }} <br />
view value : {{ form.name.$viewValue }} , Type : {{ getType(form.name.$viewValue) }} <br />
<input type="text" name="name" ng-model="formData.name" my-datetime-convert /><br /> </div>
</form>
</div>
<script src="../../js/ng-1.3.10/angular.js"></script>
<script>
var app = angular.module("app", []);
app.directive("myDatetimeConvert", [function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, elem, attrs, ngModel) {
ngModel.$formatters.push(function (value) {
return value.toDateString(); //把 datetime 各式转换成 string 格式.
});
ngModel.$parsers.push(function (value) {
try {
return new Date(value);
} catch (e) {
return undefined;
}
});
}
}
}]);
app.controller("ctrl", ["$scope", "$timeout", function ($scope, $timeout) {
$scope.formData = {
name : new Date()
};
$scope.getType = function (value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
}]);
</script>

上面就是一个处理 datetime 的例子。

$formatters 触发当 model -> view

$parsers 触发当 view -> model

5.2 ng-model-options

ng-model-options="{ updateOn: 'blur' , debounce: 2000 }"

updateOn 表示当什么 event 触发时写入 $viewValue ,  debounce 表示delay多久后把 $viewValue 同步去 $modelValue

上面这个case , 如果我们写入一个 "keatkeat" , 当onblur 时 $viewValue 马上会是 "keatkeat" , 2秒后 $modelValue 会是 "keatkeat" .

值得注意的是 : 如果我们只是写了一个 debounce , 那么 $viewValue 并不会马上有"keatkeat",而是 2 秒后  $viewValue 和 $modelValue 同时是 "keatkeat" . 建议不一起使用 !

5.3 ng-model 属性方法

方法 :

$render

render中文是渲染,当$modelValue 被修改 $digest 后会同步到 $viewValue (中间经过 pipeline) , 之后angular会调用 $render.

在做自定义指令时,我们就是靠注册这个方法来完成我们 dom 修改的。

在方法中,我们应该使用 $viewValue 工作,而不是 $modelValue 哦。

$rollbackViewValue

调用这个方法,$modeValue 的值将同步到 $viewModel 上

<input type="text" name="name" ng-model="formData.name" ng-model-options="{ updateOn: 'blur' }" ng-keyup="keyup($event,form.name)" />

$scope.keyup = function (event, ngModel) {
if (event.keyCode == 27) {
ngModel.$rollbackViewValue();
}
}

一般上是配合 keyup Esc 和 updateOn : 'blur' 使用

$commitViewValue

这个和 $rollbackViewValue 相反,是马上把 $viewValue 同步到 $modelValue 上。

属性 :

$validators

顾名思义就是做验证的啦,1.3以前我们是通过pipeline来做验证的,很麻烦。

现在呢用 $validators 就可以了

<div ng-app="app" ng-controller="ctrl">
<form novalidate autocomplete="off">
<div ng-form="form">
model value : {{ form.name.$modelValue }}<br />
view value : {{ form.name.$viewValue }}<br />
error : {{ form.name.$error | json }}
<input type="text" name="name" ng-model="formData.name" ng-model-options="{ debounce: 2000 }" my-valid />
<br />
</div>
</form>
</div>
<script src="../../js/Stooges.js"></script>
<script src="../../js/ng-1.3.10/angular.js"></script>
<script>
var app = angular.module("app", []);
app.directive("myValid", [function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, elem, attrCollection, ngModel) {
ngModel.$validators["myValid"] = function (modelValue, viewValue) {
return modelValue == "kknd";
}
}
}
}]);
app.controller("ctrl", ["$scope", "$timeout", function ($scope, $timeout) {
$scope.formData = { name: "kknd" };
}]);
</script>

$asyncValidators & $pending

而且还支持异步的

<div ng-app="app" ng-controller="ctrl">
<form novalidate autocomplete="off">
<div ng-form="form">
model value : {{ form.name.$modelValue }}<br />
view value : {{ form.name.$viewValue }}<br />
error : {{ form.name.$error | json }} <br />
pending : {{ form.name.$pending }}
<input type="text" name="name" ng-model="formData.name" ng-model-options="{ debounce: 1000 }" my-valid />
<br />
</div>
</form>
</div>
<script src="../../js/Stooges.js"></script>
<script src="../../js/ng-1.3.10/angular.js"></script>
<script>
var app = angular.module("app", []);
app.directive("myValid", ["$q",function ($q) {
return {
restrict: "A",
require: "ngModel",
link: function (scope, elem, attrCollection, ngModel) {
ngModel.$asyncValidators["myValid"] = function (modelValue, viewValue) {
var defer = $q.defer();
log("async valid send");
setTimeout(function () {
log("async valid back");
if (modelValue == "kknd") {
defer.resolve(true);
}
else {
defer.reject(false);
}
}, 3000);
return defer.promise;
}
}
}
}]);
app.controller("ctrl", ["$scope", "$timeout", function ($scope, $timeout) {
$scope.formData = { name: "kknd33" };
}]);
</script>

$pending = { myValid : true } 表示正在验证.

注册到$asyncValidators 中的方法,我们需要返回一个 promise 对象就可以了.

验证如果不通过,$modelValue 将会是 undefined

$setViewValue

这个方法主要是用于自定义指令时,我们通过事件来更新ng model 的值

比如 input text , 就是写一个 keyup event , 当keyup 触发时就会调用 $setViewValue(inputValue);

这个方法会更新 $viewValue , $modelValue , 也会触发 pipeline , validators .

注:此方法不会触发 $digest (官方网站是这样写的啦)

But ! 我自己在1.4.5 版本用好像是会的

如果 value 和之前一样的话,digest 会触发,但是$validate 不会触发

$validate()

这个方法是手动调用验证

注:此方法不会触发 $digest (真的不会哦)

ng-form

有点懒, 这个就不怎么介绍了。

只说重点 ,下次才补上吧

<form novalidate autocomplete="off">
<div ng-form="form">
model value : {{ form.name.$modelValue }}<br />
view value : {{ form.name.$viewValue }}<br />
error : {{ form.name.$error | json }} <br />
pending : {{ form.name.$pending }}
<input type="text" name="name" ng-model="formData.name" ng-model-options="{ debounce: 1000 }" my-valid />
<div ng-click="click(form.name)">ok</div>
<br />
</div>
</form>

angular 的form 支持嵌套 , 我觉得最佳做法就是上面这个样子,最外层写一个 form , 内层全部用 div + ng-form 指令

在form 里面,每一个涉及ng-model 的节点,如果有附带 name 的话,都会直接添加进 form controllers 里面 .

所以上面 form.name 可以访问到 ngModelCtrl

form 有一个 $submitted 属性,可以用于判断是否提交。

要reset 一个form , 除了把ng-model 值 clear 完之外,还必须 $setPristine() 和 $setUntouched();

ng-model 的valid , dirty 等等都会和 form 牵连, form 也会和parent form 牵连 . (这个概念要懂)

好啦,基本上就是这样了,下次我才给一个完整的案例吧 ^^