28

i've this HTML:

<p>Hello {{name}}</p>

and the controller is:

function myCtrl(scope, service) {
    scope.name = service.getUsername(); // service.getUsername() return "World!"
}
myCtrl.$inject = ['$scope', 'originalService'];

The service works fine, so i don't paste the code here... In this case the result is "Hello world!" I changed the HTML in this way:

<p>Hello {{service.getUsername()}}</p>

But this does not work.

I changed the controller:

function myCtrl(scope, service) {
    scope.ser = service;
}
myCtrl.$inject = ['$scope', 'originalService'];

and then the HTML

<p>Hello {{ser.getUsername();}}</p>

This works!

So my question is:

Is this the only way to use the functions of a service directly in the HTML, or i'm missing something?

3 Answers 3

61

AngularJS templates can only invoke functions that are available on a scope. So, whatever approach you take you need to have your function on a scope.

If you want your service's functions to be directly invokable from a template you've got several options:

The one you've tried - that is, expose the whole service on a scope:

$scope.service = service;

and then in a template:

<p>Hello {{service.getUsername();}}</p>

This is one-liner in a controller and makes all the service methods available on a scope and thus to templates.

Expose methods one by one

to have precise control over what gets exposed:

$scope.getUsername = service.getUsername;

and then in a template:

<p>Hello {{getUsername();}}</p>

This requires more work exposing methods but gives you fine-grained control over what gets exposed.

Expose proxing methods:

$scope.getMyUsername = function() {
   //pre/post processing if needed 
   return service.getUsername();
};

You can use any of those methods or mix and combine them but at the end of the day a function must end up on a scope (either directly or through another object exposed on a scope).

Sign up to request clarification or add additional context in comments.

3 Comments

Good answer. I would avoid adding the whole service object to the scope though, if it's not some type of view service and your template needs all the functionality of the serive. You generally only want to add the data/functions on the scope that your template needs and nothing more.
@AndersEkdahl I agree, probably you don't want to use this method very often. But I guess all depends on the service. I'm just merely presenting options here, there are different trade offs to be considered.
If your are using the "expose only the needed method" solution and your service is calling some of its own internal methods via "this", then you need to wrap your exposure in a "bind" : $scope.method = (service.method).bind(service);
14

Another way to do it:

Expose the service on $rootScope:

$rootScope.service = service;

and then in a template:

<p>Hello {{service.getUsername();}}</p>

You can do this on app.run, and you will get the service in all the views of your app. You could use this method for Authentication services.

1 Comment

That's dirty. I love it !
1

Another way to expose your service within your $scope would be to add a function pointer to your service method/data object.

scope.serviceData = service.data;
// Or
scope.getServiceData = service.getData;

Within your view you can then invoke it by using parentheses.

<input ng-model="serviceData().key" />
// Or
<input ng-model="getServiceData().key" />
// Or
{{getServiceData().key}}

I personally like this approach and i am currently using it in order to keep multiple views in sync with the same data. It does bring up some issues though as explained here: AngularJS. Best practice concerning proper two way data binding from a service

As to exposing to much data i am currently trying to do something like this.

// Within your view.
{{getServiceDataByKey('key')}}

// In your controller.
scope.getServiceDataByKey = service.getServiceDataByKey;

// In your service.
getServiceDataByKey : function (key) {
   return dataObject[key];
}

The reason why i am doing this is that we want to keep the controllers as clean as possible and have all our data in one centralized place. Also most data within the service should be exposed.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.