AngularJS 几个复杂的控件:编辑一个完整的对象

例子

自定义控件不必将自己限制在诸如基元之类的琐碎事物上;它可以编辑更多有趣的东西。这里我们提供两种类型的自定义控件,一种用于编辑人员,一种用于编辑地址。地址控件用于编辑人员的地址。一个使用示例是:

<input-person ng-model="data.thePerson"></input-person>

<input-address ng-model="data.thePerson.address"></input-address>

此示例的模型有意简化:

function Person(data) {

  data = data || {};

 this.name= data.name;

 this.address=data.address? new Address(data.address) : null;

}

function Address(data) {

  data = data || {};

 this.street= data.street;

 this.number= data.number;

}

地址编辑器:

app.directive('inputAddress', function() {

    InputAddressController.$inject = ['$scope'];

    function InputAddressController($scope) {

        this.$scope = $scope;

       this._ngModel= null;

       this.value= null;

       this._unwatch= angular.noop;

    }

    InputAddressController.prototype.setNgModel = function(ngModel) {

       this._ngModel= ngModel;

        

        if( ngModel ) {

            // 关键点 3

            ngModel.$render = this._render.bind(this);

        }

    };

    

    InputAddressController.prototype._makeWatch = function() {

        // 关键点 1

       this._unwatch= this.$scope.$watchCollection(

            (function() {

                return this.value;

            }).bind(this),

            (function(newval, oldval) {

                if( newval !== oldval ) { // 跳过初始触发器

                    this._ngModel.$setViewValue(newval !== null ? new Address(newval) : null);

                }

            }).bind(this)

        );

    };

    

    InputAddressController.prototype._render = function() {

        // 关键点 2

        this._unwatch();

       this.value= this._ngModel.$viewValue ? new Address(this._ngModel.$viewValue) : null;

        this._makeWatch();

    };

    return {

        restrict: 'E',

        scope: {},

        bindToController: true,

        controllerAs: 'ctrl',

        controller: InputAddressController,

        require: ['inputAddress', 'ngModel'],

        link: function(scope, elem, attrs, ctrls) {

            ctrls[0].setNgModel(ctrls[1]);

        },

        template:

            '<div>' +

                '<label><span>Street:</span><input type="text" ng-model="ctrl.value.street" /></label>' +

                '<label><span>Number:</span><input type="text" ng-model="ctrl.value.number" /></label>' +

            '</div>'

    };

});

关键点:

  1. 我们正在编辑一个对象;我们不想直接更改从父级提供给我们的对象(我们希望我们的模型与不变性原则兼容)。因此,我们在正在编辑的对象上创建一个浅表监视,并在属性更改时更新模型。我们将副本传递给我们的父母。$setViewValue()

  2. 每当模型从外部发生变化时,我们都会复制它并将副本保存到我们的作用域中。再次不变性原则,虽然内部副本不是一成不变的,但外部副本很可能是。此外,我们重建 watch ( ),以避免触发 watcher 由模型推送给我们的更改。(我们只希望手表在 UI 中进行更改时触发。)this_unwatch();this._makeWatch();

  3. 除了以上几点,我们像简单控件一样实现和调用(参见评级示例)。ngModel.$render()ngModel.$setViewValue()

人员自定义控件的代码几乎相同。该模板正在使用<input-address>. 在更高级的实现中,我们可以在可重用模块中提取控制器。

app.directive('inputPerson', function() {

    InputPersonController.$inject = ['$scope'];

    function InputPersonController($scope) {

        this.$scope = $scope;

       this._ngModel= null;

       this.value= null;

       this._unwatch= angular.noop;

    }

    InputPersonController.prototype.setNgModel = function(ngModel) {

       this._ngModel= ngModel;

        

        if( ngModel ) {

            ngModel.$render = this._render.bind(this);

        }

    };

    

    InputPersonController.prototype._makeWatch = function() {

       this._unwatch= this.$scope.$watchCollection(

            (function() {

                return this.value;

            }).bind(this),

            (function(newval, oldval) {

                if( newval !== oldval ) { // 跳过初始触发器

                    this._ngModel.$setViewValue(newval !== null ? new Person(newval) : null);

                }

            }).bind(this)

        );

    };

    

    InputPersonController.prototype._render = function() {

        this._unwatch();

       this.value= this._ngModel.$viewValue ? new Person(this._ngModel.$viewValue) : null;

        this._makeWatch();

    };

    return {

        restrict: 'E',

        scope: {},

        bindToController: true,

        controllerAs: 'ctrl',

        controller: InputPersonController,

        require: ['inputPerson', 'ngModel'],

        link: function(scope, elem, attrs, ctrls) {

            ctrls[0].setNgModel(ctrls[1]);

        },

        template:

            '<div>' +

                '<label><span>Name:</span><input type="text" ng-model="ctrl.value.name" /></label>' +

                '<input-address ng-model="ctrl.value.address"></input-address>' +

            '</div>'

    };

});

注意:这里的对象是类型化的,即它们有适当的构造函数。这不是强制性的;模型可以是普通的 JSON 对象。在这种情况下,只需使用而不是构造函数。另一个优点是控制器对于两个控件变得相同,并且可以很容易地提取到某个通用模块中。angular.copy()

小提琴:https : //jsfiddle.net/3tzyqfko/2/

提取了控制器通用代码的两个版本的小提琴:https : //jsfiddle.net/agj4cp0e/和https://jsfiddle.net/ugb6Lw8b/

以上是 AngularJS 几个复杂的控件:编辑一个完整的对象 的全部内容, 来源链接: utcz.com/z/335516.html

回到顶部