angularjs делится конфигурацией данных между контроллерами

0

Мне интересно, что может быть хорошим способом поделиться директивой между контроллером. У меня есть два директивы для использования в разных контроллерах с другой конфигурацией первое, что я думал о используя:

//html
<body data-ng-controller="MainCtrl">
    <div class="container">
        <div data-ui-view></div>
    </div>
</body>

//js
.controller('MainCtrl', function ($scope,$upload) {
    /*File upload config*/
    $scope.onFileSelect = function($files) {
        for (var i = 0; i < $files.length; i++) {
          var file = $files[i];
          $scope.upload = $upload.upload({
                url: 'server/upload/url', 
                method: 'POST',
                data: {myObj: $scope.myModelObj},
                file: file,
          }).progress(function(evt) {
            console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
          }).success(function(data, status, headers, config) {

            console.log(data);
          });

        }
    };
    /* Datepicker config */
    $scope.showWeeks = true;
    $scope.minDate = new Date();
    $scope.open = function($event) {
        $event.preventDefault();
        $event.stopPropagation();
        $scope.opened = true;
    };
    $scope.dateOptions = {
        'year-format': "'yy'",
        'starting-day': 1
    };
    $scope.format = 'MMM d, yyyy';
})
.controller('IndexCtrl', function ($scope) {

})

делая это, я могу использовать все функции в контроллере моих детей но я не очень люблю из-за проблем с столкновением. Поскольку вы не можете использовать услугу (вы не можете использовать $scope в сервисе), другие альтернативы могли бы сделать другую директиву или поместить код в блок выполнения но это совершенно одинаково с использованием родительского контроллера, поэтому о чем вы думаете?

ОБНОВЛЕНИЕ

Что вы думаете об этом подходе?

//outside of angular stauff
function MyTest(){
    this.testScope = function(){
        console.log('It works');
    }
}

//inside a controller
$scope.ns = new MyTest();

//in the view
<p ng-click="ns.testScope()">ppp</p>

RIUPDATE это кажется лучшим вариантом:)

MyTest.call($scope);
Теги:
angular-ui
angularjs-scope
angularjs-directive
angular-ui-bootstrap

4 ответа

6
Лучший ответ

Рассмотрим метод, описанный в этом сообщении: Расширение контроллеров AngularJS с использованием шаблона Mixin

Вместо того, чтобы копировать свои методы из службы, создайте базовый контроллер, который содержит эти методы, а затем вызовите расширение на своих производных контроллерах, чтобы их смешивать. Пример из сообщения:

function AnimalController($scope, vocalization, color, runSpeed) {

    var _this = this;

    // Mixin instance properties.
    this.vocalization = vocalization;
    this.runSpeed = runSpeed;

    // Mixin instance methods.
    this.vocalize = function () {
        console.log(this.vocalization);
    };

    // Mixin scope properties.
    $scope.color = color;

    // Mixin scope methods.
    $scope.run = function(){
        console.log("run speed: " + _this.runSpeed );
    };
}

Теперь мы можем микшировать AnimalController в DogController:

function DogController($scope) {

    var _this = this;

    // Mixin Animal functionality into Dog.
    angular.extend(this, new AnimalController($scope, 'BARK BARK!', 'solid black', '35mph'));

    $scope.bark = function () {
        _this.vocalize(); // inherited from mixin.
    }
}

И затем используйте DogController в нашем шаблоне:

<section ng-controller="DogController">
    <p>Dog</p>

    <!-- Scope property mixin, displays: 'color: solid black' -->
    <p ng-bind-template="color: {{ color }}"></p>

    <!-- Calls an instance method mixin, outputs: 'BARK BARK!' -->
    <button class="btn" ng-click="bark()">Bark Dog</button>

    <!-- Scope method mixin, outputs: 'run speed: 35mph' -->
    <button class="btn" ng-click="run()">Run Dog</button>
</section>

Контроллеры в этом примере находятся в глобальном пространстве и включены в разметку следующим образом.

<script type="text/javascript" src="lib/jquery.js"></script>
<script type="text/javascript" src="lib/angular.js"></script>
<script type="text/javascript" src="app/controllers/animal-controller.js"></script>
<script type="text/javascript" src="app/controllers/dog-controller.js"></script>
<script type="text/javascript" src="app/controllers/cat-controller.js"></script>
<script type="text/javascript" src="app/app.js"></script>

Я не тестировал его, но я не понимаю, почему следующее не будет работать:

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

.controller('AnimalController', ['$scope', 'vocalization', 'color', 'runSpeed', function ($scope, vocalization, color, runSpeed) { /* controller code here */}]);

.controller('DogController', ['$scope', '$controller', function($scope, $controller) {
    var _this = this;

    // Mixin Animal functionality into Dog.
    angular.extend(this, $controller('AnimalController', {
         $scope: scope,
         vocalization: 'BARK BARK!', 
         color: 'solid black', 
         runSpeed:'35mph' 
    }));

    $scope.bark = function () {
        _this.vocalize(); // inherited from mixin.
    }
}]);

см. docs для службы $controller

  • 0
    Это именно то, что я ищу СПАСИБО :)
  • 0
    Если подумать, как это сделать, не используя глобально-определенное определение контроллера?
Показать ещё 3 комментария
3

То, что вы хотите, ужасно.

Вы не хотели бы, чтобы ваши контроллеры знали что-либо друг о друге, не говоря уже о том, что у вас есть доступ к функции другого. Вы можете просто использовать Сервис для достижения этого. Что касается использования директив, не уверен, что именно вы хотите.

Что касается вашей второй вещи, вы можете так же легко сделать это

.service('MyTestService', function(){
    return {
       testScope: function(){
           console.log('It works');
       }
    };
})

.controller('MyController', ['$scope', 'MyTestService', function($scope, MyTestService){
   $scope.testScope = MyTestService.testScope;
}])

и на ваш взгляд:

<p ng-click="testScope()">ppp</p>
  • 0
    Спасибо за точку. Как насчет MyTest.call ($ scope); это кажется довольно опрятным как решение ...
  • 1
    Я очень волнуюсь по поводу всего, что включает объекты глобальной области видимости, но да, это будет работать, пока вы получаете $ scope, чтобы быть правильным. Вы можете использовать этот шаблон для тестирования дыма, но я бы не стал использовать его в рабочем коде.
Показать ещё 1 комментарий
0

очевидное, но блестящее решение (может быть)

(function(window, angular, undefined) {
                'use strict';
                angular.module('ctrl.parent', [])
                    .run(function ($rootScope) {
                        $rootScope.test = 'My test'   
                        $rootScope.myTest = function(){
                            alert('It works');
                        }
                });
            })(window, angular);
            angular.module('app',['ctrl.parent'])
                .controller('ChildCtrl', function($scope){

            });

Это легко и чисто и не видит никакого недостатка (это не глобально)

ОБНОВЛЕНИЕ

'use strict';
                (function(window, angular, undefined) {
                    'use strict';
                    angular.module('ctrl.parent', [])
                        .controller('ParentController',function (scope) {
                            scope.vocalization = '';
                            scope.vocalize = function () {
                                console.log(scope.vocalization);
                            };
                    });
                })(window, angular);
                angular.module('app',['ctrl.parent'])
                    .controller('ChildCtrl', function($scope,$controller){
                    angular.extend($scope, new $controller('ParentController', {scope:$scope}));
$scope.vocalization = 'CIP CIP';
                });

немного аккуратно и работает CIP CIP:)

  • 0
    Недостаток заключается в том, что вы используете $ rootScope в качестве родительского контроллера - что произойдет, если вам потребуется более одного родительского контроллера? Будет лучше, если вы определите свои родительские контроллеры в угловом модуле как контроллеры, а затем создадите его экземпляр с помощью службы $ controller. Я обновлю свой ответ примером, чтобы вы могли понять, что я имею в виду.
  • 0
    Я снова обновился :) спасибо за точку. Как вы думаете ? Я просто упрощаю твой код
Показать ещё 1 комментарий
0

Я закончил с:

//service
.service('PostUploader',function($upload){
        var that = this;
        var fileReaderSupported = window.FileReader !== null;
        this.notify = null;
        this.success = null;
        this.showAlert = false;
        this.avatar = '';
        this.onFileSelect = function($files) {
            var $file = $files[0];
            var filename = $file.name;
            this.avatar = filename;
            var isImage = /\.(jpeg|jpg|gif|png)$/i.test(filename);
            if(!isImage){
                this.showAlert = true;
                return;
            }
            this.showAlert = false;
            if (fileReaderSupported && $file.type.indexOf('image') > -1) {
                var fileReader = new FileReader();
                fileReader.readAsDataURL($file);
                fileReader.onload = that.notify;
            }
            $upload.upload({
                url :'/api/post/upload',
        method: 'POST',
        headers: {'x-ng-file-upload': 'nodeblog'},
        data :null,
        file: $file,
        fileFormDataName: 'avatar'
            })
            .success(that.success)
            .progress(function(evt) {

            })
            .error(function(data, status, headers, config) {
                throw new Error('Upload error status: '+status);
            })

        };
        this.closeAlert = function() {
            this.showAlert = false;
        };
    })    

//controller
 /* Uploader post */
        $scope.dataUrl = null;
        $scope.avatar = PostUploader.avatar;
        $scope.showAlert = PostUploader.showAlert;
        $scope.onFileSelect = PostUploader.onFileSelect;
        $scope.closeAlert = PostUploader.closeAlert;
        PostUploader.notify = function(e){
            $timeout(function() {
                $scope.dataUrl = e.target.result;
            });
        };
        PostUploader.success = function(data, status, headers, config) {
           $timeout(function() {
                $scope.post.avatar = data.url;
            });
        }
        $scope.$watch('avatar',function(newVal, oldVal){
            if(newVal) { 
                $scope.avatar = newVal;
            }  
        }); 
        $scope.$watch('showAlert',function(newVal, oldVal){
            $scope.showAlert = newVal;
            $scope.dataUrl = null;
        }); 

Я сделал это, потому что я должен делать то же самое в создании сообщения и редактирования сообщения, но в целом У меня такой же повторяющийся код!:)

Единственное, что есть в коде, имеет меньше логики.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню