Two-way binding between service and controller without $scope.$watch. Is this a bad practice?

老子叫甜甜 提交于 2020-01-03 17:47:18

问题


I've heard, that service should not be linked to scope variable in controller because view gains direct access to service. But i want to bind my scope variable to data that stored in service, and i want that variable to reflect all changes from service. I've read a lot of workaround, and in most of them were told to use $scope.$watch, if i want to watch service data from controller. I've wrote simple example without using of $scope.$watch, which is working exactly like i want, but i'm definitely not sure, can i use something like this, or it this a bad practice. I'm learning angular for about 2-3 days, and very need your advice:

html:

<div ng-controller="TestController">
    <p>Current value = {{ serviceData.getValue() }}</p>
    <input type="text" ng-model="newValue">
    <button ng-click="changeServiceData(newValue)">Change</button>
</div>

module.js

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

controller.js

app.controller('TestController', function($scope, testService){
    $scope.serviceData = testService.getPublicData();
    $scope.changeServiceData = function(newValue){
        testService.setValue(newValue);
    }
});

service.js

app.factory('testService', function(){
    var value = null;
    return {
        setValue: function(newValue){
            value = newValue;
        },
        getPublicData: function(){
            return {
                getValue: function(){
                    return value;
                }
            }
        }
    }
});

Summarizing , view has access only to getters. To update data i'm using service, which i can inject in any controller, and all changes in service are reflected on controller, and on view.

UPDATE: I have tried to change my factory like this:

app.factory('testService', function(){
var value = null;
return {
    setValue: function(newValue){
        value = newValue;
    },
    getValue: function(){
        return value;
    }
}

});

and assign getter to scope:

app.controller('TestController', function($scope, testService){
    $scope.value = testService.getValue();
    $scope.changeServiceData = function(newValue){
        testService.setValue(newValue);
    }
});

In this case, if i changing value in service from view using setter, value doesnt changing implictly in view, it doesnt reflect actual service data. Maybe you could explain such behaviour?


回答1:


Your update is almost right, if you've decided to use a service containing a variable it is meant to be shared accross modules and controllers.

What you need to do is only use this getter and setter now:

app.controller('TestController', function($scope, testService){
  $scope.testService = testService;
  $scope.newValue    = 'initial-value';
});

And in your HTML:

<div ng-controller="TestController">
  <p>Current value = {{ testService.getValue() }}</p>
  <input type="text" ng-model="newValue">
  <button ng-click="testService.setValue(newValue)">Change</button>
</div>

Now we still put value into the scope because apparently you want to update the service value only on click, so it need to be desynchronized from the service itself.

If you want to bind the service value directly into the ngModel of that input, you cannot use a getter but will have to use the variable directly:

<input ng-model="testService.value">

Or one last option is to propagate any changes made to newValue using the ngChange directive:

<input ng-model="newValue" ng-change="testService.setValue(newValue)">


来源:https://stackoverflow.com/questions/33904608/two-way-binding-between-service-and-controller-without-scope-watch-is-this-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!