Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/375.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 什么';扩展AngularJS控制器的推荐方法是什么?_Javascript_Angularjs_Dry - Fatal编程技术网

Javascript 什么';扩展AngularJS控制器的推荐方法是什么?

Javascript 什么';扩展AngularJS控制器的推荐方法是什么?,javascript,angularjs,dry,Javascript,Angularjs,Dry,我有三个非常相似的控制器。我想要一个控制器,这三个控制器可以扩展并共享其功能。您不需要扩展控制器。如果它们执行相同的基本功能,则需要将这些功能移动到服务。可以将该服务注入控制器。您可以尝试以下方法(尚未测试): module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) { // Initialize the super class and extend it

我有三个非常相似的控制器。我想要一个控制器,这三个控制器可以扩展并共享其功能。

您不需要扩展控制器。如果它们执行相同的基本功能,则需要将这些功能移动到服务。可以将该服务注入控制器。

您可以尝试以下方法(尚未测试):

module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
    // Initialize the super class and extend it.
    angular.extend(this, $controller('CtrlImpl', {$scope: $scope}));
    … Additional extensions to create a mixin.
}]);

对于继承,可以使用标准JavaScript继承模式。 下面是一个使用
$injector

function Parent($scope) {
  $scope.name = 'Human';
  $scope.clickParent = function() {
    $scope.name = 'Clicked from base controller';
  }    
}

function Child($scope, $injector) {
  $injector.invoke(Parent, this, {$scope: $scope});
  $scope.name = 'Human Child';
  $scope.clickChild = function(){
    $scope.clickParent();
  }       
}

Child.prototype = Object.create(Parent.prototype);
如果您使用
controllerAs
语法(我极力推荐),那么使用经典继承模式就更容易了:

function BaseCtrl() {
  this.name = 'foobar';
}
BaseCtrl.prototype.parentMethod = function () {
  //body
};

function ChildCtrl() {
  BaseCtrl.call(this);
  this.name = 'baz';
}
ChildCtrl.prototype = Object.create(BaseCtrl.prototype);
ChildCtrl.prototype.childMethod = function () {
  this.parentMethod();
  //body
};

app.controller('BaseCtrl', BaseCtrl);
app.controller('ChildCtrl', ChildCtrl);
另一种方法是只创建“抽象”构造函数,它将是您的基本控制器:

function BaseController() {
  this.click = function () {
    //some actions here
  };
}

module.controller('ChildCtrl', ['$scope', function ($scope) {
  BaseController.call($scope);
  $scope.anotherClick = function () {
    //other actions
  };
}]);

好吧,我不太确定你想要实现什么,但通常服务才是你想要实现的目标。 还可以使用Angular的作用域继承特性在控制器之间共享代码:

<body ng-controller="ParentCtrl">
 <div ng-controller="FirstChildCtrl"></div>
 <div ng-controller="SecondChildCtrl"></div>
</body>

function ParentCtrl($scope) {
 $scope.fx = function() {
   alert("Hello World");
 });
}

function FirstChildCtrl($scope) {
  // $scope.fx() is available here
}

function SecondChildCtrl($scope) {
  // $scope.fx() is available here
}

函数ParentCtrl($scope){
$scope.fx=函数(){
警报(“你好世界”);
});
}
函数FirstChildCtrl($scope){
//$scope.fx()在此处可用
}
函数SecondChildCtrl($scope){
//$scope.fx()在此处可用
}
也许您不扩展控制器,但可以扩展控制器或使单个控制器成为多个控制器的混合体

module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
    // Initialize the super class and extend it.
    angular.extend(this, $controller('CtrlImpl', {$scope: $scope}));
    … Additional extensions to create a mixin.
}]);
创建父控制器时,也会执行其中包含的逻辑。 有关更多信息,请参阅$controller(),但只需传递
$scope
值。所有其他值将正常注入

@mwarren,你的问题通过角度依赖注入神奇地自动解决了。您所需要的只是注入$scope,尽管您可以根据需要重写其他注入的值。 以以下为例:

(函数(角度){
var module=angular.module('stackoverflow.example',[]);
module.controller('simpleController',函数($scope,$document){
this.getOrigin=函数(){
返回$document[0]。location.origin;
};
});
module.controller('complexController',function($scope,$controller){
extend(this,$controller('simpleController',{$scope:$scope}));
});
})(角度)

来自控制器的原点:{C.getOrigin()}

您可以通过服务工厂提供商进行扩展。它们是相同的,但具有不同程度的灵活性

以下是使用factory的示例:

在这里,您还可以使用存储功能:

<div ng-controller="myController">
    <input ng-blur="myFactory.store()" />
</div>

这是另一个很好的解决方案:


只需注入服务,就可以在任何控制器中创建服务并继承其行为

app.service("reusableCode", function() {

    var reusableCode = {};

    reusableCode.commonMethod = function() {
        alert('Hello, World!');
    };

    return reusableCode;
});
然后在要从上述可重用代码服务扩展的控制器中:

app.controller('MainCtrl', function($scope, reusableCode) {

    angular.extend($scope, reusableCode);

    // now you can access all the properties of reusableCode in this $scope
    $scope.commonMethod()

});
演示PLUNKER:

您可以将角度“as”语法与普通JavaScript继承结合使用

请参阅此处的更多详细信息

您可以直接使用$controller('ParentController',{$scope:$scope}) 范例


为此,我编写了一个函数:

function extendController(baseController, extension) {
    return [
        '$scope', '$injector',
        function($scope, $injector) {
            $injector.invoke(baseController, this, { $scope: $scope });
            $injector.invoke(extension, this, { $scope: $scope });
        }
    ]
}
您可以这样使用它:

function() {
    var BaseController = [
        '$scope', '$http', // etc.
        function($scope, $http, // etc.
            $scope.myFunction = function() {
                //
            }

            // etc.
        }
    ];

    app.controller('myController',
        extendController(BaseController,
            ['$scope', '$filter', // etc.
            function($scope, $filter /* etc. */)
                $scope.myOtherFunction = function() {
                    //
                }

                // etc.
            }]
        )
    );
}();
优点:

  • 您不必注册基本控制器
  • 所有控制器都不需要知道$controller或$injector服务
  • 它与angular的数组注入语法配合得很好,这对于javascript的小型化是必不可少的
  • 您可以轻松地将额外的可注入服务添加到基本控制器,而无需记住将它们添加到所有子控制器,并从中传递它们
  • 缺点:

  • 基本控制器必须定义为一个变量,这有可能污染全局范围。在我的使用示例中,我通过将所有内容包装在一个匿名自执行函数中来避免这种情况,但这确实意味着所有子控制器都必须在同一个文件中声明
  • 此模式适用于直接从html实例化的控制器,但不适用于通过$controller()服务从代码创建的控制器,因为它依赖于注入器,因此无法直接从调用代码中注入额外的非服务参数

  • 我认为延长控制器是不好的做法。而是将共享逻辑放入服务中。javascript中的扩展对象往往变得相当复杂。如果您想使用继承,我建议您使用typescript。不过,在我看来,精简控制器是更好的选择。

    谢谢,但我有4个功能已经在使用服务(保存、删除等),并且在所有三个控制器中都存在相同的功能。如果扩展不是一个选项,是否有“混合”的可能性?@vladexologija我同意巴特的观点。我认为服务是混合的。您应该尝试将尽可能多的逻辑移出控制器(进入服务)。因此,如果您有3个控制器需要执行类似的任务,那么服务似乎是正确的方法。扩展控制器在Angular中感觉不自然。@vladexologija这里有一个例子来说明我的意思:它非常基本,但你会明白的。如果没有任何论证和进一步的解释,答案是毫无用处的。我还认为你有点错过了OP的要点。已经有一个共享服务。您唯一要做的就是直接公开该服务。我不知道这是不是个好主意。如果需要访问范围,您的方法也会失败。但是按照您的推理,我会将作用域作为作用域的属性显式地公开给视图,以便将其作为参数传递。一个典型的例子是,您的站点上有两个表单驱动的报表,每个报表都依赖于大量相同的数据,并且每个报表都使用大量共享服务。从理论上讲,您可以尝试将所有单独的服务放在一个包含数十个AJAX调用的大型服务中,然后使用ha
    module.controller('Parent', ['$scope', function ($scope) {
        //code
    }])
    
    module.controller('CtrlImplAdvanced', ['$scope', '$controller', function ($scope, $controller) {
        //extend parent controller
        $controller('CtrlImpl', {$scope: $scope});
    }]);
    
    function extendController(baseController, extension) {
        return [
            '$scope', '$injector',
            function($scope, $injector) {
                $injector.invoke(baseController, this, { $scope: $scope });
                $injector.invoke(extension, this, { $scope: $scope });
            }
        ]
    }
    
    function() {
        var BaseController = [
            '$scope', '$http', // etc.
            function($scope, $http, // etc.
                $scope.myFunction = function() {
                    //
                }
    
                // etc.
            }
        ];
    
        app.controller('myController',
            extendController(BaseController,
                ['$scope', '$filter', // etc.
                function($scope, $filter /* etc. */)
                    $scope.myOtherFunction = function() {
                        //
                    }
    
                    // etc.
                }]
            )
        );
    }();