【问题标题】:Angular Reusing Directives and controllersAngular 重用指令和控制器
【发布时间】:2015-09-04 11:29:05
【问题描述】:

我编写了一个自定义下拉选项选择器,一切都很好,它具有获取数据(从传入的 url)来填充列表的功能。

现在我想做的是重用这个组件但是...... 当我将它添加到应用程序的另一部分,但使用不同的数据集时,它会复制数据并多次运行控制器功能。

据我所知 1 有两个问题,服务是单例的,所以当我运行该函数来填充一些数据时,因为只有一个服务实例,它只是将它添加到当前数据集。

那么另一个问题是控制器确实有实例,所以现在有两个,它运行每个中的功能。

因此,简单的解决方案是复制组件并将其命名为不同的名称,虽然这可能会解决问题,但如果我想重复使用 10 次,那就是同一个组件的 10 个副本,不好。

我来自 OOP Java 背景,所以我可能正在尝试在不支持它的语言中使用这些技术;)

所以我知道我必须重新考虑如何做到这一点,但我遇到了一些困难,最好的方法是什么?

这是(希望如此)一个 JSFiddle,它说明了我正在运行的内容

var app = angular.module('myApp',[]);

app.directive('mySelector', function () {
return {
 scope: {
      mydata: '='
    },
    restrict: 'EA',
    template:'<select ng-model="timePeriodSelection" ng-options="timePeriodOption.name for timePeriodOption in timePeriodOptions"><option value="">Choose time period</option></select>',
controller: function($scope, myService) {
    //$scope.name = 'Superhero';
    console.log('test',$scope.mydata);
    myService.setData($scope.mydata);
    $scope.timePeriodOptions = myService.getData();
  console.log('test2',myService.getData());
    }
 };
});

app.factory('myService', function() {
var _data=[];    
return {
    setData: function(value){
        for (var a=0;a<value.length;a++){
            _data.push(value[a]);
        }
    },
    getData: function(){
        return _data
    }            
}
});

https://jsfiddle.net/devonCream/ess9d6q6/

出于商业原因,我无法向您展示我拥有的代码,但想象一下我传入的实际上是一个 url,我有一个服务可以获取数据,然后将其存储在服务/工厂的数组中,每次运行时,它都会不断添加它们!该代码是一个模拟演示。

【问题讨论】:

  • 您能否提供所有代码并在 plunker 中突出显示问题? (你可以 fork 和编辑这个plnkr.co/edit/b8sxOLNgGKZ36oQDGJLM?p=preview
  • 遗憾的是,自从它关闭源代码以来,我已经设置了一个 jsfiddle 来展示我的问题,

标签: javascript angularjs oop controller singleton


【解决方案1】:

像自定义下拉菜单这样的东西应该是一个指令,而不是别的。也就是说,有很多方法可以实现你想要用指令做的事情。查看directive walkthroughs,他们真的很有帮助。

以某种方式,您可能希望拥有一个隔离范围、使用模板并添加一个链接函数。

项目始终相同的示例:

angular.module('myApp')
    .directive('myDropdown', function () {
        return {

            scope: {},

            template: '' +
                '<div class="my-dropdown">' +
                    '<div class="my-dropdown-item" ng-repeat="item in items">{{item.text}}</div>' +
                '</div>',

            link: function (scope, element, attrs) {
                scope.items = ['Item 1', 'Item 2', 'Item 3'];
            }

        };
    });

将项目传递给每个实例的示例:

angular.module('myApp')
    .directive('myDropdown', function () {
        return {

            scope: {
                items: '='
            },

            template: '' +
                '<div class="my-dropdown">' +
                    '<div class="my-dropdown-item" ng-repeat="item in items">{{item.text}}</div>' +
                '</div>'

        };
    });

--更新--

在服务中获取数据的示例:

angular.module('myApp')
    .service('dataService', function ($http) {
        var items;

        $http.get('http://ab.com/dropdown-items')
        .then(function (res) {
            items = res.data;
        });

        return {
            items: items
        };
    })
    .directive('myDropdown', function (dataService) {
        return {

            scope: {},

            template: '' +
                '<div class="my-dropdown">' +
                    '<div class="my-dropdown-item" ng-repeat="item in items">{{item.text}}</div>' +
                '</div>',

            link: function (scope, element, attrs) {
                scope.items = dataService.items;
            }

        };
    });

【讨论】:

  • 好的,我有类似的东西,但我在哪里保存数据?我们被告知将数据保存在工厂/服务中,但这样做会给我带来重复问题,我需要在其他服务中访问这些数据才能访问其他服务。
  • 你能举一个更具体的例子来说明你在谈论什么类型的数据吗?用户输入的数据、构成下拉选项的数据,还有其他什么?
  • 数据来自返回 XML 的服务,我将其转换为 json,然后存储数组(在工厂中),问题出现是因为获取数据的调用存在于控制器中,因为控制器有多个实例,被多次调用并添加到数组中。续。
  • 我目前的解决方法是使用一个变量,传递给控制器​​,以识别正在使用哪个实例,然后在那个实例上触发数据请求,对我来说感觉有点“笨拙”,但我可以看到解决问题的唯一方法,除了将数据存储在控制器中,我再次被告知这是不好的做法。
  • 也许可以调用以获取服务中的数据并让您的指令使用该服务。查看更新的答案。
【解决方案2】:

因此,除非有人能以不同的方式告诉我,否则我能看到解决问题的唯一方法是将数据保存在控制器中,因此将数据隔离到它自己的控制器实例中。将数据保存在其他任何地方只会导致实例问题。

我重构了我的“小提琴”以显示 2 个不同的数据源(在此示例中,我使用 2 个工厂作为模型),将数据带回控制器进行处理然后存储。

通常,如果我不重用组件,我会将这个逻辑放入工厂,但这样做会给我带来我必须从头开始的问题。

此外,在我的“真实”项目中,我检查变量以“查看”触发了哪些“实例”并从中调用方法,一切似乎有点笨拙,但它似乎是我可以让它工作的唯一可靠方法Angular 2 将解决这些问题。

Anyway my link to my jsfiddle

    var app = angular.module('myApp',[]);

app.directive('mySelector', function () {
return { 
    scope: true,
    bindToController:  {
        mydata: '@mydata',     
        timePeriodOptions: '='
    },
    controllerAs: 'selCtrl',
    restrict: 'EA',
    template:'<select ng-model="timePeriodSelection" ng-options="timePeriodOption.name for timePeriodOption in selCtrl.timePeriodOptions"><option value="">Choose time period</option></select>',
    controller: 'selCtrl'
 };
});    
app.controller('selCtrl', function($scope, myService) {
    var selCtrl = this;    
    selCtrl.timePeriodOptions = [];
    if (angular.isString(selCtrl.mydata)){
        processData();
    }
    function processData(){
        var value = myService.getData(selCtrl.mydata);
        for (var a=0;a<value.length;a++){
            selCtrl.timePeriodOptions.push(value[a]);
        }
    };
});

app.factory('myService', function(dataModel1,dataModel2) {
return {
    getData: function(model){
        var _data = []        
        if (model === "1"){
            _data = dataModel1.getData();
        }else{
            _data = dataModel2.getData();
        }
        console.log('data ',_data);
        return _data
    }            
    }
});
app.factory('dataModel1', function() {
    var _data=[{"name":1,"value":1},{"name":2,"value":2},{"name":3,"value":3}];    
    return {
        getData: function(){
            return _data
        }            
    }
});
app.factory('dataModel2', function() {
    var _data=[{"name":4,"value":4},{"name":5,"value":5},{"name":6,"value":6}];    
    return {
        getData: function(){
            return _data
        }            
    }
});

【讨论】:

    猜你喜欢
    • 2017-06-05
    • 1970-01-01
    • 1970-01-01
    • 2016-06-14
    • 1970-01-01
    • 1970-01-01
    • 2016-07-12
    • 1970-01-01
    相关资源
    最近更新 更多