javascript - 通过 ref 将 $scope.property 注入(inject)工厂实例

标签 javascript angularjs watch

我需要一个可以与 $scope.property 一起应用的 Factory 对象来获取结果。我还需要知道工厂实例中的修饰符或 $scope.property 是否发生更改以更新结果。当然,我对这种模式的看法可能是错误的。

app.factory('MyFactory',
    function () {

        var MyFactory = function (name, modifier) {
            this.name = name;
            this.result = 0;
            this.modifier = modifier;
        }

        //I might want to call this when modifier or MyProperty changes
        MyFactory.prototype.modifyingMethod = function () {
            this.result = this.modifier * //externalProperty;
        }

        MyFactory.prototype.watcher = function () {
            //no idea what I will do here or if I need this at all
            // I need to recalculate the result like with $watch
            this.modifyingMethod();
        }

        return MyFactory;
    }
)

app.controller('MyCtrl'
    function($scope, MyFactory) {

        $scope.MyProperty = 42;

        $scope.MyFactoryOptions = [
            new MyFactory('Option1', 1),
            new MyFactory('Option2', 2),
            new MyFactory('Option3', 3),
            new MyFactory('Option4', 4),
            new MyFactory('Option5', 5)
        ];
    }

所以我有一个问题,我需要 $watch MyProperty 和修饰符(它可以由用户更改),以便我可以更改结果。如果 Property 是值类型,则将其传递到 Factory 构造函数将不起作用。也许我可以在返回 MyProperty 中传递一个函数。

我可以在工厂设置内部 $watch 吗?如果我要在工厂外部的 Controller 中执行此操作,则需要为每个实例执行此操作。我是否应该在我的工厂对象上设置某种注册方法?

有什么建议、模式或我可能想要使用的东西吗?

最佳答案

基本上,您可以将 Factory 理解为对象集合的接口(interface)(数组或关联数组,分别是纯 JavaScript 对象)。

我发现您使用对象的方法非常有吸引力,并且我相信您可以实现类似的目标。我仍然整理了一个 fiddle ,它展示了我将如何解决问题:

MVC 模式中,您的 Factory 将是模型, Controller 应尽可能简单,带有指令的 HTML 表示 View 。

您的 Controller 监视来自用户的更改($scope.MyProperty$watch)。虽然模型能够 self 意识到任何依赖的外部属性的变化。请注意,只有当 ExternalObject 服务/工厂的更改不是原始值时,这些更改才会被识别。这就是为什么在 ExternalObject 工厂中我返回整个对象。

在完美的世界中,您不需要间隔一段时间监听更改,但会收到一个 JavaScript 事件。如果可能的话,就去做吧!请注意,如果您想查看 View 中的更改,超出 Angular 范围的对象更新将需要您执行 $scope.$apply()$interval$timeout 都调用 $scope.apply(),因此使用它们是最佳实践。

实际上,这段代码中仍然需要进行大量清理工作,但它可能会让您了解如何使用替代结构:

var app = angular.module('yourApp', []);
window.yourGlobalObject = {};

setInterval(function () {
    yourGlobalObject.externalProperty = Math.floor(Math.random() * 5000);
}, 1000);

app.factory('ExternalObject', ['$window', function ($window) {
    return $window.yourGlobalObject;
}]);

app.factory('MyFactory', ['$interval', 'ExternalObject', function ($interval, ExternalObject) {
    var options = [{
        name: 'Option1',
        modifier: 1
    }, {
        name: 'Option2',
        modifier: 2
    }, {
        name: 'Option3',
        modifier: 3
    }],
        cachedExternalProperty = 0,
    cachedMyProperty = 0;

    MyFactory = {
        getOptions: function () {
            return options;
        },
        addOption: function (name, modifier) {
            options.push({
                name: name,
                modifier: modifier
            });
        },
        setMyProperty: function (value) {
            cachedMyProperty = value;
        },
        setResults: function (myProperty) {
            angular.forEach(options, function (option, key) {
                option.result = option.modifier * ExternalObject.externalProperty * myProperty;
            });
            console.log(options);
        }
    };

    // let the service check for updates in the external property, if changed
    $interval(function () {
        if (cachedExternalProperty !== ExternalObject.externalProperty) {
            cachedExternalProperty = ExternalObject.externalProperty;
            MyFactory.setResults(cachedMyProperty);
        }
    }, 1000);

    return MyFactory;
}]);

app.controller('MyCtrl', ['$scope', 'MyFactory', function ($scope, MyFactory) {

    $scope.MyProperty = 42;
    $scope.MyFactoryOptions = MyFactory.getOptions();
    $scope.setResults = function () {
        MyFactory.setResults($scope.MyProperty);
    };
    
    $scope.$watch('MyProperty', function (value) {
        MyFactory.setMyProperty(value)
        MyFactory.setResults(value);
    });

}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body>
    <section ng-app="yourApp" ng-controller="MyCtrl">
        <button ng-click="setResults(MyProperty)">Update Results</button>
        <div ng-repeat="factory in MyFactoryOptions">{{factory.name}} {{factory.result}}</div>
        
        <input type="number" ng-model="MyProperty">
    </section>
</body>

关于javascript - 通过 ref 将 $scope.property 注入(inject)工厂实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28991746/

相关文章:

javascript - 选定节点与其导入节点之间的差异

AngularJS,使用自定义过滤器的组件

javascript - Angular : Watch for class change not working

asp.net-core - 在 vscode 中调试时观看 C# 代码

javascript - 错误: Attempted to handle event `didSetProperty` when Deleting record model ember

使用大纲 View 的 Aptana JavaScript 开发

javascript - 如何制作 Instagram "Open in app"按钮?

angularjs - 最佳实践 : $rootScope or child $scope in unit tests?

angularjs - 观察变量并更改它

javascript - 如何解释在 Protractor 中使用 browser.sleep