A
A
Alexey Yarkov2016-03-14 15:35:54
Angular
Alexey Yarkov, 2016-03-14 15:35:54

$scope.$watch and some magic. Where is the mistake?

We watch a demo with an open console: DEMO
We have a dataService.js service

/*global angular*/

(function() {
    'use strict';

    angular
        .module('App')
        .service('dataService', ['$http', dataService]);
        
    function dataService($http){
    	var self = this;
    	
        self.data = [
        {
          "id": "bf2ff391-b5f1-44f5-9fcf-c7cd081dd290",
          "url": "mail.ru",
          "login": "user",
          "password": "password"
        },
        {
          "id": "dbf66cd2-89d9-4a20-a303-18c5703ec510",
          "url": "toster.ru",
          "login": "user",
          "password": "password"
        },
        {
          "id": "f7d50ae5-c3a6-4bc7-8d4b-adf711e19462",
          "url": "ya.ru",
          "login": "user",
          "password": "password"
        }
      ];
        
        self.columnNames = ['№', 'URL страницы', 'Логин', 'Пароль'];
        
    /**
     * Метод загрузит из localStorage список учетных данных, если он там есть и он не пуст.
     *
     * @method getLocalData
     *
     * @return {Array} Список учетных данных.
     */
        self.getLocalData = function(){
            // Если ключ с именем "data" существует в localStorage
      if (localStorage["data"]) {
        var data = JSON.parse(localStorage["data"]);
        // Если это массив и он не пустой
        if (angular.isArray(data) && data.length > 0) {
          self.data = data;
          console.log("SERVICE LOAD:", self.data);
        }
      }
      return self.data;
        }
        
    /**
     * Метод сохранит в localStorage список учетных данных, переданный в параметре dataArray.
     *
     * @method setLocalData
     * 
     * @param  {Array} dataArray Список учетных данных.
     *
     * @return {Array} Список учетных данных.
     */
        self.setLocalData = function(dataArray){
        	self.data = dataArray;
            localStorage["data"] = JSON.stringify(dataArray);
            console.log("SERVICE SAVE:", self.data);
        }
    }
    
    dataService.$inject = ['$http'];

})();

And AppCtrl.js controller
/*global angular*/

(function() {
    'use strict';

  angular
      .module('App')
    .controller('AppCtrl', ['$scope', 'dataService', 'cryptoService', AppCtrl]);

  /**
   * Основной контроллер приложения.
   *
   * @method AppCtrl
   *
   * @param  {dependence} $scope Основная зависимость контроллера.
   *
   * @param  {AngularService} dataService Сервис для получения данных для формирования списка записей.
   * 
   * @param  {AngularService} cryptoService Сервис содержащий криптографические методы.
   */
  function AppCtrl($scope, dataService, cryptoService) {
    /* jshint validthis: true */
    var vm = this;

    vm.addFormUrl = '';
    vm.addFormLogin = '';
    vm.addFormPassword = '';
    vm.selectedAll = false;
    // Загружаем названия заголовков таблицы из localStorage
    vm.columnNames = dataService.columnNames;
    // Загружаем список учетных данных из localStorage
    vm.data= dataService.getLocalData();


    /**
     * Метод добавит элемент в список учетных записей.
     *
     * @method addItem
     */
    vm.addItem = function () {
      // Избегаем записи пустых полей
      if ((!vm.addFormUrl || vm.addFormUrl.length < 1) || 
        (!vm.addFormLogin || vm.addFormLogin.length < 1) || 
        (!vm.addFormPassword || vm.addFormPassword.length < 1)) {
        return;
      }
      
      var uuid = cryptoService.getUUID();

      // Добавляем запись в список
      vm.data.push({
        id: uuid, // Получаем из метода сервиса значение для id записи
        url: vm.addFormUrl,
        login: vm.addFormLogin,
        password: vm.addFormPassword
      });

      // Подчищаем за собой
      vm.addFormUrl = '';
      vm.addFormLogin = '';
      vm.addFormPassword = '';
    }

    /**
     * Метод удалит элемент из списка на текущей строке.
     *
     * @method removeItem
     *
     * @param  {Number} index Индекс элемента в массиве Model.data.
     *
     * @return {Null} Ничего не возвращает.
     */
    vm.removeItem = function (index) {
      try{
        vm.data.splice(index, 1);
      }
      catch(e){

      }
    }

    /**
     * Метод удалит все отмеченные чекбоксами элементы из списка.
     *
     * @method removeAllSelected
     *
     * @return {Null} Ничего не возвращает.
     */
    vm.removeAllSelected = function () {
      // Найдем все элементы массива, у которых 'selected' == true
      var rItems = vm.data.findAll({'selected': true});
      // В цикле пройдемся по найденному массиву и удалим все элементы
      angular.forEach(rItems, function(item){
        var index = vm.data.indexOf(item);
        if(index > -1){
          vm.data.splice(index, 1);
        }
      });
      // Подчищаем за собой
      rItems = null;
      // Снимаем выделение с чекбоксов
      vm.selectedAll = false;
    }

    /**
     * Метод выделит или снимет выделение со всех чекбоксов в списке.
     *
     * @method allItemsToggleSelection
     *
     * @return {Null} Ничего не возвращает.
     */
    vm.allItemsToggleSelection = function () {
      if (vm.selectedAll) {
        vm.selectedAll = true;
      } else {
        vm.selectedAll = false;
      }
      angular.forEach(vm.data, function (item) {
        item.selected = vm.selectedAll;
      });
    }

    // Следим за изменениями списка учетных данных и поддерживаем в localStorage актуальное состояние
    $scope.$watch(
      'vm.data',
      function (newVal, oldVal, scope) {
        console.log("$scope.$watch is worked:", vm.data);
        dataService.setLocalData(vm.data);
      },
      true
    );

  }

  AppCtrl.$inject = ['$scope', 'dataService', 'cryptoService'];
  
})();

So. Before the removal of the logic to the service, everything worked. Now $watch works once when the application is loaded and no longer reacts to vm.data changes. That is, elements are removed and added, but are not stored in localStorage.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexey Yarkov, 2016-03-14
@yarkov

I asked it myself - I'll answer it myself)))
Infa from here: stackoverflow
The whole problem is in the scope, as I understand it. In general, we change the code to this:

$scope.$watch(
  angular.bind(vm, function () { 
    return vm.data;
  }),
  function (newVal, oldVal, scope) {
    console.log("$scope.$watch is worked:", vm.data);
    if (newVal) {
      dataService.setLocalData(vm.data);
    }
  },
  true
);

And enjoy))

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question