3

I'm trying to share a service value between 2 controllers, but the two-way data binding isn't working. Is it possible doing that without using ng-model?

// script.js
angular.module("MyApp")
    .factory("ValuesStore", function() {

        var service = {};

        service.visible = true;
        service.toggle = toggle;

        function toggle() {
            console.log(service.visible);
            service.visible = !service.visible;
        }

        return service;
    });

function FirstController($scope, ValuesStore) {
    $scope.visible = ValuesStore.visible;

    $scope.toggle = ValuesStore.toggle;
}

function SecondController($scope, ValuesStore) {
    $scope.visible = ValuesStore.visible;
}

<!-- template -->
<div ng-controller="FirstController">
    {{ visible }}
</div>

<div ng-controller="SecondController">
    {{ visible }}
</div>

All the examples I have seen use input elements with ng-model. Maybe I should do this using watchers or broadcast.

Aurelio
  • 24,702
  • 9
  • 60
  • 63
juanmorschrott
  • 573
  • 5
  • 25

3 Answers3

3

In your controller, bind to service directly.

function FirstController($scope, ValuesStore) {
    $scope.ValuesStore = ValuesStore;
}

function SecondController($scope, ValuesStore) {
    $scope.ValuesStore = ValuesStore;
}

Then in your view, you can access the property by

{{ ValuesStore.visible }}

Once you trigger ValuesStore.Toggle(), they can be updated automatically.

But just like @devqon said, maybe you don't want to involve the whole service in your controller, $watch can help you out.

In your first controller, watch visible

$scope.visible = ValuesStore.visible;

$scope.$watch('visible', function (newValue, oldValue) {
    if (newValue !== oldValue) {
        ValueStore.visible = newValue;
    }
});

In your second controller, keep an eye on ValuesStore.visible

$scope.visible = ValuesStore.visible;

$scope.$watch(ValueStore.visible, function (newValue, oldValue) {
    if (newValue !== oldValue) {
        ValueStore.visible = newValue;
    }
});
Rebornix
  • 5,272
  • 1
  • 23
  • 26
  • 2
    I don't think you want the whole service in your view. That could be considered bad practice – devqon May 29 '15 at 08:23
  • @devqon It's an easy to handle data sharing together with bindings, but you are right, sometimes we don't want the whole service. `$watch` is another option, see my update. – Rebornix May 29 '15 at 08:30
2

Try:

$scope.$watch(function(){
    return ValuesStore.visible;
}, function (newValue) {
    $scope.visible = newValue
});

Taken from this example: http://jsfiddle.net/TheSharpieOne/RA2j7/2/

num8er
  • 18,604
  • 3
  • 43
  • 57
1

You need to store visible variable inside some object so that it will use javascript prototypal inheritance, value of scope will update everywhere on the view without putting watcher on the variable. Lets say we create a variable called variables that would have value of visible so that it would reflect the changes on each controller. You need to add your whole service reference to controller scope so that all the service variable will available on html like $scope.ValuesStore = ValuesStore;

Markup

  <div ng-controller="FirstController">
    <div ng-click="ValuesStore.toggle()">{{ ValuesStore.variables.visible }}</div>
  </div>

  <div ng-controller="SecondController">
     <div ng-click="ValuesStore.toggle()">{{ ValuesStore.variables.visible }}</div>
  </div>

Code

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

function FirstController($scope, ValuesStore) {
  $scope.ValuesStore = ValuesStore;
}

function SecondController($scope, ValuesStore) {
  $scope.ValuesStore = ValuesStore;
}

angular.module("plunker")
  .service("ValuesStore", function() {

    this.variables = {};

    this.variables.visible = true;

    this.toggle = function() {
      console.log(this.variables.visible);
      this.variables.visible = !this.variables.visible;
    }
  });

Demo Plunkr

Community
  • 1
  • 1
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299