Введение $scope в угловую сервисную функцию()



у меня есть:



angular.module('cfd')
.service('StudentService', [ '$http',
function ($http) {
// get some data via the $http
var path = 'data/people/students.json';
var students = $http.get(path).then(function (resp) {
return resp.data;
});
//save method create a new student if not already exists
//else update the existing object
this.save = function (student) {
if (student.id == null) {
//if this is new student, add it in students array
$scope.students.push(student);
} else {
//for existing student, find this student using id
//and update it.
for (i in students) {
if (students[i].id == student.id) {
students[i] = student;
}
}
}
};


но когда я называю save(), у меня нет доступа к $scope, и сделать ReferenceError: $scope is not defined. Поэтому логическим шагом (для меня) является предоставление save () с помощью $scope, и поэтому я также должен предоставить / ввести его в service. Так что если я делаю это так:



  .service('StudentService', [ '$http', '$scope',
function ($http, $scope) {


Я получаю следующую ошибку:




ошибка: [$injector:unpr] неизвестный поставщик: $scopeProvider




ссылка в ошибке (Вау, это аккуратно!) дайте мне знать, что это связано с инжектором и может иметь отношение к порядку объявления файлов js. Я попытался переупорядочить их в index.html, но я думаю, что это что-то более простое, например, я вводил их.



использование Angular-UI и Angular-UI-Router

588   6  

6 ответов:

The $scope то, что вы видите, вводится в контроллеры, не является какой-то Службой (как и остальная часть вводимого материала), но является объектом Scope. Многие объекты области могут быть созданы (обычно прототипически наследуя от родительской области). Корень всех областей является $rootScope и вы можете создать новую дочернюю область с помощью $new() метод любой области (включая $rootScope).

цель области состоит в том, чтобы "склеить" презентацию и бизнес-логику вашего приложение. Это не имеет большого смысла, чтобы пройти $scope в сервис.

службы-это одноэлементные объекты, используемые (среди прочего) для обмена данными (например, между несколькими контроллерами) и обычно инкапсулируют многоразовые фрагменты кода (поскольку они могут быть введены и предлагать свои "услуги" в любой части вашего приложения, которое нуждается в них: контроллеры, директивы, фильтры, другие службы и т. д.).

я уверен, что разные подходы будут работать для вас. Один из них таков:
Поскольку StudentService отвечает за работу с данными студентов, вы можете иметь StudentService держите массив студентов и пусть он "поделиться" его с тем, кто может быть заинтересован (например, ваш $scope). Это имеет еще больший смысл, если есть другие представления / контроллеры / фильтры / службы, которые должны иметь доступ к этой информации (если их нет прямо сейчас, не удивляйтесь, если они скоро начнут появляться).
Каждый раз, когда новый студент добавляется (с помощью сервиса save() метод), собственный массив сервиса учащиеся будут обновлены, и каждый другой объект, совместно использующий этот массив, также будет автоматически обновляться.

исходя из описанного выше подхода, ваш код может выглядеть так:

angular.module('cfd', [])

.factory('StudentService', ['$http', function ($http) {
    var path = 'data/people/students.json';
    var students = [];

    /* In the real app, instead of just updating the students array
     * (which will be probably already done from the controller)
     * this method should send the student data to the server */
    var save = function (student) {
        if (student.id === null) {
            students.push(student);
        } else {
            for (var i = 0; i < students.length; i++) {
                if (students[i].id === student.id) {
                    students[i] = student;
                    break;
                }
            }
        }
    };

    /* Populate the students array with students from the server */
    $http.get(path).success(function (data) {
        data.forEach(function (student) {
            students.push(student);
        });
    });

    return {
        students: students,
        save:     save
    };     
}])

.controller('someCtrl', ['$scope', 'StudentService', 
    function ($scope, StudentService) {
        $scope.students = StudentService.students;
        $scope.saveStudent = function (student) {
            // Do some $scope-specific stuff

            // Do the actual saving using the StudentService
            StudentService.save(student);
            // The $scope's `students` array will be automatically updated
            // since it references the StudentService's `students` array

            // Do some more $scope-specific stuff, 
            // e.g. show a notification 
        };
    }
]);

Одна вещь, которую вы должны быть осторожны при использовании этого подхода,-это никогда не назначать массив службы, потому что тогда любые другие компоненты (например, области) будут по-прежнему ссылаться на исходный массив, и ваше приложение сломается.
Например, чтобы очистить массив в StudentService:

/* DON'T DO THAT   */  
var clear = function () { students = []; }

/* DO THIS INSTEAD */  
var clear = function () { students.splice(0, students.length); }

Смотрите также, это короткое демо.


НЕБОЛЬШОЕ ОБНОВЛЕНИЕ:

несколько слов, чтобы избежать путаницы, которая может возникнуть при разговоре об использовании сервиса, но не создавая его с помощью

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

angular.module('cfd')
    .controller('MyController', ['$scope', 'StudentService', function ($scope, StudentService) {

        $scope.students = null;

        (function () {
            $scope.$watch(function () {
                return StudentService.students;
            }, function (newVal, oldVal) {
                if ( newValue !== oldValue ) {
                    $scope.students = newVal;
                }
            });
        }());
    }]);

одна вещь, чтобы отметить, что в пределах вашей службы, для того, чтобы students свойство должно быть видимым, оно должно быть на объекте сервиса или this вот так:

this.students = $http.get(path).then(function (resp) {
  return resp.data;
});

хорошо (долго) ... если вы настаиваю иметь $scope доступ внутри службы, вы можете:

создать службу getter / setter

ngapp.factory('Scopes', function (){
  var mem = {};
  return {
    store: function (key, value) { mem[key] = value; },
    get: function (key) { return mem[key]; }
  };
});

введите его и сохраните область контроллера в нем

ngapp.controller('myCtrl', ['$scope', 'Scopes', function($scope, Scopes) {
  Scopes.store('myCtrl', $scope);
}]);

теперь, получить область внутри другой службы

ngapp.factory('getRoute', ['Scopes', '$http', function(Scopes, $http){
  // there you are
  var $scope = Scopes.get('myCtrl');
}]);

службы являются синглетами, и не логично вводить область в Службу (что действительно так, вы не можете вводить область в службу). Вы можете передать область в качестве параметра, но это также плохой выбор дизайна, потому что у вас будет область, редактируемая в нескольких местах, что затрудняет отладку. Код для работы с переменными области должен входить в контроллер, а вызовы службы - в службу.

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

проблема, с которой вы столкнулись, заключается в том, что вы не знаете, что http-вызовы выполняются асинхронно, что означает, что вы не получаете значение сразу, как могли бы. Например,

var students = $http.get(path).then(function (resp) {
  return resp.data;
}); // then() returns a promise object, not resp.data

есть простой способ обойти это и поставить функцию обратного вызова.

.service('StudentService', [ '$http',
    function ($http) {
    // get some data via the $http
    var path = '/students';

    //save method create a new student if not already exists
    //else update the existing object
    this.save = function (student, doneCallback) {
      $http.post(
        path, 
        {
          params: {
            student: student
          }
        }
      )
      .then(function (resp) {
        doneCallback(resp.data); // when the async http call is done, execute the callback
      });  
    }
.controller('StudentSaveController', ['$scope', 'StudentService', function ($scope, StudentService) {
  $scope.saveUser = function (user) {
    StudentService.save(user, function (data) {
      $scope.message = data; // I'm assuming data is a string error returned from your REST API
    })
  }
}]);

В форма:

<div class="form-message">{{message}}</div>

<div ng-controller="StudentSaveController">
  <form novalidate class="simple-form">
    Name: <input type="text" ng-model="user.name" /><br />
    E-mail: <input type="email" ng-model="user.email" /><br />
    Gender: <input type="radio" ng-model="user.gender" value="male" />male
    <input type="radio" ng-model="user.gender" value="female" />female<br />
    <input type="button" ng-click="reset()" value="Reset" />
    <input type="submit" ng-click="saveUser(user)" value="Save" />
  </form>
</div>

этого удалены некоторые бизнес-логики для краткости и я на самом деле не проверял код, но что-то вроде этого будет работать. Основная концепция заключается в передаче обратного вызова от контроллера к службе, которая вызывается позже в будущем. Если вы знакомы с NodeJS, это та же концепция.

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

(function () {
    getDataFactory = function ($http)
    {
        return {
            callWebApi: function (reqData)
            {
                var dataTemp = {
                    Page: 1, Take: 10,
                    PropName: 'Id', SortOrder: 'Asc'
                };

                return $http({
                    method: 'GET',
                    url: '/api/PatientCategoryApi/PatCat',
                    params: dataTemp, // Parameters to pass to external service
                    headers: { 'Content-Type': 'application/Json' }
                })                
            }
        }
    }
    patientCategoryController = function ($scope, getDataFactory) {
        alert('Hare');
        var promise = getDataFactory.callWebApi('someDataToPass');
        promise.then(
            function successCallback(response) {
                alert(JSON.stringify(response.data));
                // Set this response data to scope to use it in UI
                $scope.gridOptions.data = response.data.Collection;
            }, function errorCallback(response) {
                alert('Some problem while fetching data!!');
            });
    }
    patientCategoryController.$inject = ['$scope', 'getDataFactory'];
    getDataFactory.$inject = ['$http'];
    angular.module('demoApp', []);
    angular.module('demoApp').controller('patientCategoryController', patientCategoryController);
    angular.module('demoApp').factory('getDataFactory', getDataFactory);    
}());

Comments

    Ничего не найдено.