Задать вопрос

Cannot read property 'data' of undefined, после Ajax, Rivets.js?

Всем привет ! Использую библиотеку rivets,js
При клике по кнопке, добавляю в localStorage объекты, все отлично работает, как только через аjax я обновил контент с кнопками, после клика выдает ошибку -> Cannot read property 'data' of undefined.
В этой конструкции:
var goods = model.data.zakazi.filter(function (goods) {
                  return goods.ID === ID;
          })[0];

Не пойму как с ней бороться
Вот код:
Такая конструкция
var controller = {

  onAtbClick: function(e, model) {
       var ID = $(this).data("main-id");
       console.log(data );
          var goods = model.data.zakazi.filter(function (goods) {
                 return goods.ID === ID;
          })[0];

        model.data.zakazi.push({
              ID: ID,
              quantity: 1

            });
   },
   saveData: function(data) {
    localStorage.setItem( 'g_zakazi', JSON.stringify( data ) );
   }
}

После успешного ajax, запускается функция

function toTopAfterAjaxUpdatePagination()
  {
      var scrollGoods = $('section.goods').offset().top;
      $(document).scrollTop(scrollGoods - 50);
      
      $('.goods__list').children('.goods__item').find('.goods__tocart').bind('click', controller.onAtbClick);
      console.log('Ураааа поднялись');

      var userData = JSON.parse(localStorage.getItem('g_zakazi')) || {
        title: 'Welcome',
        juzer_id: $('#juzer-id').text(),
        subtotal: 0,
        zakazi: []
      };

      rivets.bind($('#rivetsSpace'), {data: userData, controller: controller});

      console.log(userData );
  }

var data = JSON.parse(localStorage.getItem('g_zakazi')) || {
    title: 'Welcome',
    juzer_id: $('#juzer-id').text(),
    subtotal: 0,
    zakazi: []
  };

rivets.bind(
  document.querySelector('#rivetsSpace'),
  {
    data: data,
    controller: controller
  }

    );

HTML кнопки моей такой
<p data-text="Добавить в корзину" class="goods__tocart" data-main-id="179" rv-on-click="controller.onAtbClick"><span>Добавить</span></p>

Заранее спасибо !!!
  • Вопрос задан
  • 1841 просмотр
Подписаться 1 Оценить 10 комментариев
Решения вопроса 1
lazalu68
@lazalu68
Salmon
В общем проблема была в повторной инициализации приложения и попытке установки обработчика для элемента управления приложения сторонними средствами - с помощью jQuery.

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

$.ajax({
    url: '/demo.php',
    type: 'POST',
    data: data,
    success: function (html) {
        $goods_list.empty().append(html);
        rivets.bind($goods_list, model);
        toTopAfterAjaxUpdatePagination();
    }
});


Изменённый код main.js
var $ = jQuery;

$(function(){
  var $goods_list = $('ul.goods__list'),
      model = {
        data: JSON.parse(localStorage.getItem('g_zakazi')) || {
          title: 'Welcome',
          //juzer_id: $('#juzer-id').text(),
          subtotal: 0,
          zakazi: []
        },
        controller: controller
      };

  rivets.bind(document.querySelector('#rivetsSpace'), model);

  $('.goods__pagination').on('click', '.goods__page', function(){

    console.log('Клик по пагинации');
    var data = { id: $(this).text() };

        $.ajax({
            url: '/demo.php',
            type: 'POST',
            data: data,
            success: function (html) {
                //console.log(data);
                $goods_list.empty().append(html);
                rivets.bind($goods_list, model);
                toTopAfterAjaxUpdatePagination();
            }
        });
  });

});

function returnFalse(){
  console.log('Выходим');
  return false;
}

var controller = {

  onAtbClick: function(e, model) {
       var ID = $(this).data("id");

          var goods = model.data.zakazi.filter(function (goods) {
                  return goods.ID === ID;
          })[0];

          if (goods) {
              goods.quantity++;
              returnFalse();

          } else {

            model.data.zakazi.push({
                  ID: ID,
                  quantity: 1

                });
          }

		model.controller.updatePrice(model.data);
		model.controller.saveData(model.data);

   },

   updatePrice: function(data) {
    var zakazi = data.zakazi,
      product,
      subtotal = 0;

    data.subtotal = subtotal;

  },

   removeGoods: function(e, model) {

        e.stopImmediatePropagation();

        var index = model.index,
            zakazi = model.data.zakazi;

      zakazi.splice(index, 1);
      model.controller.saveData(model.data);

    },
	
   saveData: function(data) {
    localStorage.setItem( 'g_zakazi', JSON.stringify( data ) );
   }
}

function toTopAfterAjaxUpdatePagination() {
  var scrollGoods = $('section.goods').offset().top;
  $(document).scrollTop(scrollGoods - 50);
}



rivets.formatters.length = function(val) {
  return val.length;
};
Вариант решения который не подошёл

Не знаю как это вообще делают, но у меня получилось решить с помощью индивидуального байнда для каждого элемента. Можно было конечно и с помощью компонента оформить, было бы красивее и проще, но в целом это уже детали, можно сделать как нравится. Вот архив. То есть теперь при загрузке приложения в глобальной области видимости создаётся массив для инициализации блока goods:

window.items = [
	{ id: 1 },
	{ id: 2 },
	{ id: 3 },
	...
]

При инициализации приложения этот массив обрабатывается с помощью функции контроллера processGoods:

model.$goods_list.append( controller.processGoods(window.items, model) );
...
var controller = {
    processGoods: function(data, model) {
      var elements = new Array(data.length),
          temp_fragment = document.createDocumentFragment();

      for (var i = 0; i < data.length; i++) {
        elements[ i ] = model.controller.createElementFromTemplate('goods__item', model);
        rivets.bind(elements[i], Object.assign({ item: data[i] }, model));
        temp_fragment.appendChild( elements[ i ] );
      }

      return temp_fragment;
    },
    createElementFromTemplate: function(item, model) {
      return document.importNode(model.templates[ item ].content.children[0], true);
    },
    ...
}

Также эта функция участвует при обработке данных пришедших от pagination запроса:

$('.goods__pagination').on('click', '.goods__page', function() {
    var data = {
        id: $(this).text()
    };
    $.ajax({
        url: '/demo.php',
        type: 'POST',
        data: data,
        dataType: 'json',
        success: function(data) {
            model.$goods_list.empty().append( controller.processGoods(data, model) );
            toTopAfterAjaxUpdatePagination();
        }
    });
});
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
У объекта model отсутствует свойство data, вы выведите в console.log объект model, а не data, может станет понятно.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы