Search code examples
javascriptangularjsmodel-view-controllerangular-servicesangular-controller

How do I hide data from one controller but share it with another controller using a shared service


I just discovered how to share data between controllers using a service that stores an array and passes it by reference to the second controller.

Is there a way that the Service can protect the array from the first controller as that controller is only required pass an item to the service. The array is only used by the second controller.

  • ModalController - accepts input from user
  • MyService - takes the input from the user and stores it in an array -
  • ActionController - has a reference to the MyService array and displays it on the view

Above is the basic structure of the app.

Here is a jsfiddle of it


Solution

  • It looks like you're overdoing it. This cannot be done by means of the framework, and this cannot be solved by means of JavaScript, since the language has no access control.

    MyService has both getChore and passChore methods as its public interface, and any unit that uses the service can both methods too. This is perfectly fine. If both controllers are developed by yourself and you have no real reasons to restrict the access, apply Occam's razor here and don't look any further.

    If this were a library that is developed by you and will be used by third party, a method that shouldn't be used from the outside could be marked as 'internal' and named accordingly. AngularJS has the convention to prefix all internal things with $$.

    On the other hand, TypeScript is intended to augment JavaScript with types and access control, so is possible to solve it this way, at least at design time (before TS source code was compiled to JS):

    interface IWritableFooService {
        setFoo();
    }
    
    interface IDuplexFooService extends IWritableFooService {
        getFoo();
    }
    
    class FooService implements IDuplexFooService {
        getFoo() {...}
        setFoo() {...}
    }
    

    Considering that the service was defined as

    app.service('fooService', FooService);
    

    It can be injected in one place with restrictive type:

    app.controller('BarController', function (fooService: IWritableFooService) {...});
    

    And with loose type in another:

    app.controller('BazController', function (fooService: IDuplexFooService) {...});
    

    If BarController will try to use fooService.getFoo(), this will result in TypeScript compilation error.

    This approach is an example of overengineering. Even if proper interface was specified, nobody can prohibit a developer to replace IWritableFooService with IDuplexFooService type at some point. OOP best practices originate from practical considerations, and it appears that there's none. But yes, it is possible to do this with TypeScript.