Я пытаюсь выяснить, как вы правильно обрабатываете привязку, когда мои данные хранятся в сервисе.

Я могу заставить все работать, если он поместит сервис в область действия $, а затем заставит шаблоны связываться непосредственно с ним, но это кажется действительно плохой идеей.

Мне бы очень хотелось, чтобы мои представления / контроллеры могли легко изменять состояние в службе и отражать это повсюду.

Такое чувство, что я должен быть в состоянии сделать что-то вроде следующего, но это не работает (http://jsfiddle.net/aidankane/AtRVD/1/).

HTML

<div ng-controller="MyCtl">
    <select ng-model="drawing" ng-options="d.file for d in drawings"></select>
</div>
<div ng-controller="MyOtherCtl">
    {{ drawing }}
</div>

JS

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

myApp.factory('myService', function(){
    var me = {
        drawings: [{'file':'a'}, {'file':'b'}]
    };
    // selected drawing
    me.drawing = me.drawings[0];
    return me;
});

function MyCtl($scope, myService){
    // can do:
    // $scope.mys = myService;
    // and then in html ng-model="mys.drawing"
    // but that seems wrong

    $scope.drawings = myService.drawings;
    $scope.drawing = myService.drawing;

    // can I not do this? it doesn't seem to work anyway...
    $scope.$watch('drawing', function(drawing){
        myService.drawing = drawing;
    });
}

function MyOtherCtl($scope, myService){
    $scope.drawing = myService.drawing;
}

MyCtl.$inject = ['$scope', 'myService'];
MyOtherCtl.$inject = ['$scope', 'myService'];
20
Aidan Kane 25 Янв 2013 в 21:41

3 ответа

Лучший ответ

Вы можете привязать сервисы, используя $watch и передавая функцию:

$scope.$watch( function () { return myService.drawing; }, function ( drawing ) {
  // handle it here. e.g.:
  $scope.drawing = drawing;
});

А затем используйте $scope.drawing в ваших шаблонах, и они автоматически обновятся:

<div ng-controller="MyOtherCtl">
  {{ drawing }}
</div>
41
Josh David Miller 25 Янв 2013 в 17:46

Я думаю, что еще более элегантно работать с обещаниями (см. $q.deferred()) и разрешать их асинхронно. В функции обещания вы можете назначить данные членам $scope.

2
Bartłomiej Zalewski 8 Сен 2014 в 11:30

Существует два способа связывания данных из службы: 1) По значению (потребуется наблюдатель, как описано выше, для проверки изменений переменных в значении примитива службы) 2) По ссылке (значения связаны напрямую), что мой предпочтительный метод привязки данных.

Я объясню только вторую возможность, поскольку принятый ответ уже показывает, как может быть реализован наблюдатель. Этот блог очень хорошо описывает то, что я собираюсь объяснить.

Я создал этот план, чтобы проиллюстрировать привязку данных по ссылке.

Вот код из плана:

HTML

<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <script data-require="angularjs@1.5.0" data-semver="1.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="myAppCntrl">
    <h1>Hello Plunker!</h1>
    <h3>By value</h3>
    <p>{{byValue}}</p>
    <p>{{objByValue}}</p>
    <h3>By object in service reference</h3>
    <p>{{byRefence.stringPrimitive}}</p>
    <h3>By reference to service singleton</h3>
    <p>{{myservice.stringPrimitive}}</p>
    <p style="color: green">of course, you can reference an object through the service as well</p>
    <p>{{myservice.objectWithPrimitive.stringPrimitive}}</p>

    <button ng-click=update()>Update strings on service</button>
    <br />
    <button ng-click=setDefaults()>Restore Defaults</button>
  </body>

</html>

JAVASCRIPT

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

myApp.controller('myAppCntrl', function($scope, myAppService){
  $scope.myservice = myAppService;
  $scope.byValue = myAppService.stringPrimitive;
  $scope.objByValue = myAppService.objectWithPrimitive.stringPrimitive;
  $scope.byRefence = myAppService.objectWithPrimitive;

  $scope.update = function () {
    myAppService.stringPrimitive = "updated string";
    myAppService.objectWithPrimitive.stringPrimitive = "updated string here too";
  };
  $scope.setDefaults = function () {
    myAppService.stringPrimitive = 'string primitive';
    myAppService.objectWithPrimitive.stringPrimitive = 'string primitive';
  };
});

myApp.service('myAppService', function(){
  this.stringPrimitive = 'string primitive';
  this.objectWithPrimitive = {
    stringPrimitive: 'string primitive'
  };
});

Так как это работает?

Важно понимать, что это не имеет ничего общего с тем, как работает angular, и имеет много общего с тем, как работает Javascript. Когда переменная установлена равной значению примитива (или передана функции) в javascript (целое число, строка и т. Д.) , переменная устанавливается значением . Это означает, что новая переменная является копией переменной, для которой вы устанавливаете ее равной с новым местоположением в памяти. Когда переменная установлена равной объекту (или передана функции) в javascript , переменная устанавливается по ссылке .

Что это значит?

Когда переменная $ scope установлена по значению, а переменная службы изменяется, поскольку переменная $ scope является только копией переменной службы, переменная службы больше не имеет ничего общего с переменной службы и не изменится, когда служба Вар делает.

Когда переменная $ scope установлена равной и object, она назначается ссылкой. Это означает, что когда объект службы (обратите внимание, что служба является объектом, поскольку он создается с помощью нового ключевого слова, и вы можете ссылаться на этот объект с помощью «this» внутри службы) или любые объекты в службе, на которые имеются ссылки, изменяются, любая переменная $ scope, которая ссылается на эти объекты, также будет обновлена.

2
Nick Brady 5 Мар 2016 в 23:24