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>
View Code

 

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 

 

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 牵连 . (这个概念要懂)

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

 

 

 

你可能感兴趣的:(AngularJS)