javascript - How to implement a controller trait in AngularJS - Stack Overflow

I want to give a set of controllers access to methods and properties defined in a trait. Right now the

I want to give a set of controllers access to methods and properties defined in a trait. Right now the best implementation I have e up with is:

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

app.controller('MainCtrl', function($scope, CtrlTrait) {
  $scope.name = CtrlTrait.presetName;
  CtrlTrait.setGreeting.call($scope, 'Hello');
});

app.service('CtrlTrait', function() {
  this.setGreeting = function(greeting) { this.greeting = greeting; }
  this.presetName = 'tom';
});

Plunkr Code

This is fine, but I would like the properties and method to be accessible via the controller's $scope without having to manually create the alias in each controller. I want to be able to use the properties and method from the template just by having injected the service into the controller.

Is this possible, or do I have to create a [wrapper around]/[provider for] $scope like $specialCtrlScope that presets the properties and methods I want?

I want to give a set of controllers access to methods and properties defined in a trait. Right now the best implementation I have e up with is:

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

app.controller('MainCtrl', function($scope, CtrlTrait) {
  $scope.name = CtrlTrait.presetName;
  CtrlTrait.setGreeting.call($scope, 'Hello');
});

app.service('CtrlTrait', function() {
  this.setGreeting = function(greeting) { this.greeting = greeting; }
  this.presetName = 'tom';
});

Plunkr Code

This is fine, but I would like the properties and method to be accessible via the controller's $scope without having to manually create the alias in each controller. I want to be able to use the properties and method from the template just by having injected the service into the controller.

Is this possible, or do I have to create a [wrapper around]/[provider for] $scope like $specialCtrlScope that presets the properties and methods I want?

Share Improve this question asked Feb 10, 2014 at 18:39 km6zlakm6zla 4,9072 gold badges31 silver badges53 bronze badges 7
  • Could you give an example of your preferred syntax? Are you saying you would like to call $scope.setGreeting() instead of CtrlTrait.setGreeting()? – Hylianpuffball Commented Feb 10, 2014 at 18:48
  • Yes! That's exactly right. I would like to call $scope.setGreeting(). – km6zla Commented Feb 10, 2014 at 18:51
  • I think you might want to review docs.angularjs/guide/dev_guide.services.creating_services – Nathaniel Johnson Commented Feb 10, 2014 at 19:09
  • 1 Another way of saying that: A service can be an object with functions and other objects attached to it. Just return the new object from the service. Don't use this. – Nathaniel Johnson Commented Feb 10, 2014 at 19:15
  • @NathanielJohnson I reviewed the docs and I wasn't able to see the connection. What am I supposed to replace this with? – km6zla Commented Feb 10, 2014 at 19:19
 |  Show 2 more ments

4 Answers 4

Reset to default 7

You can try using angular.extend like this: angular.extend($scope,CtrlTrait); It will allows us to use in the $scope the same functions that your service. So, you can use the function directly in your html like this:

 <button ng-click="setGreeting('Good bye! ')">Good Bye</button>

Here is your plunker demo adapted:

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

app.controller('MainCtrl', function($scope, CtrlTrait) {
  $scope.name = CtrlTrait.presetName;
 // CtrlTrait.setGreeting.call($scope, 'Hello');
  angular.extend($scope,CtrlTrait);
  $scope.setGreeting('Hello World');
});

app.service('CtrlTrait', function() {
  this.setGreeting = function(greeting) { this.greeting = greeting; }
  this.presetName = 'tom';
});

http://plnkr.co/edit/BENS78mjFfpc6VCEtgK8?p=preview

You Can try the below in your controller

$scope.setGreeting = CtrlTrait.setGreeting

and can later use

$scope.setGreeting.call($scope, 'Hello');

EDIT AFTER THE COMMENT

Try this

  var app = angular.module('plunker', []);
  app.controller('MainCtrl', function($scope, CtrlTrait) {
    $scope.trait = CtrlTrait;
    $scope.name = $scope.trait.presetName;
    $scope.trait.setGreeting.call($scope,'Hello');
  });

  app.service('CtrlTrait', function() {
    var trait = {};
    trait.setGreeting = function(greeting) { this.greeting = greeting; }
    trait.presetName = 'tom';
    return trait;
  });

So I'll preface this with a disclaimer... I would not remend that you actually do this, or at least not do it in this way. You're adding extra coupling between your controllers and services inside of a framework built around modularity and injection, all for the sake of saving a few method calls.

That said, here's a way to implement what you want. (JSFiddle here)

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

var controllerMaker = function(trait,controllerCode){
    return function($scope, $injector){

        //'apply' traits to this scope
        var apply = function(trait){
            trait.applyTo($scope);
        }
        apply.$inject = [trait];
        $injector.invoke(apply);

        //Finishes the other injections
        controllerCode.$inject = ['$scope'];
        controllerCode($scope);
    };
}

//Here's a sample 'trait'
app.service('CtrlTrait', function() {
    this.applyTo = function(obj){
        obj.setGreeting = function(greeting) { this.greeting = greeting; }
        obj.presetName = 'tom';
    }
});

//Then, setup your controller like this
app.controller('GreatController', controllerMaker("CtrlTrait",function($scope){ //Not using injection though!
    $scope.bleh = $scope.presetName; //will be 'tom'
}))

There are certainly weaknesses with this, like how your controller loses injection, but if you reeeeeeally wanted to, I'm sure you could play aruond with $inject and find something that suits your needs.

Angular will inject the return value of a the function if it is an object. So in your code:

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

app.controller('MainCtrl',["$scope","DefaultName","TraitService", function($scope, defaultName, traitService) {
  $scope.name = defaultName;
  $scope.OKPressed = function() {
    traitService.setName($scope.name);
  };

});

// You can use .constant() for a constant value;

app.constant("DefaultName", "tom");

app.service('TraitService', function() {
  var traitService = {}; // The name does't matter
  traitService.setName = function(name) {
  // Not this.name = name because (this)is not guaranteed to persist or be the same across injections.
  // I am only using local storage to illustrate.  I usually use $rootScope to store 
  // Global variables. since they are always available on the $scope object without 
  // needing a service.
  // That might be a better way for you ($rootScope)
        localStorage.setItem("nameKey", name); 
  }
  traitService.getName = function () {
    return localStorage.getItem("nameKey");
  }
  return traitService; // This is what will be injected above
});

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745313901a4622127.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信