@stefan_hansch

Backbone — переход по под вкладкам по очереди, если поля все заполнены?

Здравствуйте. Я больше бэкенд разработчик. Столкнулся с backbone + marionette.

Вопрос следующий:

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

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

Вот сам код:

views/inputs/steps.js

Lib.ns('Views.Inputs', function(Inputs) {
  'use strict';

  var Empty = Mn.ItemView.extend({
    tagName: 'li',
    template: function() { return ''; }
  });

  var Tab = Mn.ItemView.extend({
    template: '#Inputs-StepTabTemplate',
    tagName: 'li',
    triggers: {click: 'select'},
    ui: {index: '[data-ui="index"]'},
    bindings: {'[data-ui="title"]': 'title'},
    onRender: function() {
      this.stickit();
      this.ui.index.html(this.getOption('index') + 1);
    }
  });

  var Tabs = Mn.CollectionView.extend({
    tagName: 'ul',
    className: 'special',
    childView: Tab,
    childEvents: {select: 'selectHandler'},

    filter: function(child) {
      return child.get('name') !== 'active_step';
    },

    childViewOptions: function(item, index) {
      return {index: index};
    },

    selectHandler: function(view) {
      this.triggerMethod('select', this.collection.indexOf(view.model));
    },

    select: function(index) {
      this.$('li').removeClass('uk-active');
      this.children.findByModel(this.collection.at(index)).$el.addClass('uk-active');
    }
  });

  var Parent = Inputs.Container;
  var Steps = Parent.extend({
    tagName: 'ul',
    className: 'uk-switcher special',
    defaultChild: Empty,

    initialize: function() {
      Parent.prototype.initialize.apply(this, arguments);
      this.collection = this.model.get('fields');
    },

    childViewOptions: function(item) {
      var opts = Parent.prototype.childViewOptions.apply(this, arguments);
      opts.tagName = 'li';
      opts.showTitle = item.has('showTitle') ? item.get('showTitle') : false;
      opts.formSection = false;
      return opts;
    }
  });

  Inputs.Steps = Mn.LayoutView.extend({
    className: 'steps',
    template: '#Inputs-StepsTemplate',

    behaviors: {
      Messageable: {el: '[data-region="messages"]'},
    },

    regions: {
      tabs:  '[data-region="step-tabs"]',
      panes: '[data-region="step-panes"]'
    },

    ui: {
      prev: '[data-ui="prev"]',
      next: '[data-ui="next"]',
      save: '[data-ui="save"]'
    },

    events: {
      'click @ui.prev': 'prevClickHandler',
      'click @ui.next': 'nextClickHandler',
      'click @ui.save': 'saveClickHandler'
    },

    childEvents: {
      next: 'nextHandler'
    },

    initialize: function() {
      var fields = this.model.get('fields');
      this.activeStep = this.model.find('active_step');
      if (!this.activeStep) {
        fields.add({name: 'active_step', type: 'integer', visible: false});
        this.activeStep = this.model.find('active_step');
        this.activeStep.setValue(0);
      }
      var step = this.getOption('step');
      if (step == null) { step = this.activeStep.getValue(); }
      if (step == null) { step = 0; }
      this.activeStep.setValue(step);
    },

    select: function(index) {
      if (!this.switcher) { return; }
      this.scrollTop();
      this.tabs.select(index);
      this.switcher.show(index);
      this.activeStep.setValue(index);
    },

    onRender: function() {
      var opts = {
        rootView: this.getOption('rootView') || this,
        collection: this.model.get('fields')
      };
      this.tabs  = new Tabs(opts);
      this.listenTo(this.tabs, 'select', this.selectHandler);
      this.fakeTabs = new Tabs(opts);
      this.steps = new Steps(_.extend(opts, {model: this.model}));
      this.getRegion('tabs').show(this.tabs);
      this.getRegion('panes').show(this.steps);
      this.fakeTabs.render();
      var step = this.activeStep.getValue();
      this.index = step;
      this.updateNavigation();
      _.defer(function(view) {
        view.switcher = UIkit.switcher(view.fakeTabs.$el, {
          connect: view.steps.$el,
          animation: 'slide-horizontal'
        });
        view.switcher.on('show.uk.switcher', _.bind(view.switchHandler, view));
        view.select(step);
      }, this);
    },

    updateNavigation: function(index) {
      if (index == null) { index = this.index; }
      if (index === 0) {
        this.ui.prev.attr('disabled', 'disabled');
      } else {
        this.ui.prev.removeAttr('disabled');
      }
      // this.tabs.collection.length - active_step - 1
      if (index === this.tabs.children.length - 1) {
        this.ui.next.find('span').html('Подготовить');
      } else {
        this.ui.next.find('span').html('Следующий шаг');
      }
    },

    setRegistered: function(registered) {
      this.registered = registered;
      if (registered) {
        this.ui.save.show();
      } else {
        this.ui.save.hide();
      }
    },

    switchHandler: function(event, item) {
      this.index = $(item).index();
      this.updateNavigation();
    },

    prevClickHandler: function() {
      if (this.index === 0) { return; }
      this.select(this.index - 1);
    },

    nextClickHandler: function() {
      var view = this.getOption('rootView') || this;
      if (this.index === this.tabs.children.length - 1) {
        if (!this.validateCurrentStep()) {
          this.scrollTop();
          return;
        }
        view.triggerMethod('create');
      } else {
        if (this.index === 0 && !this.registered) {
          view.triggerMethod('register', 1);
          return;
        }
        if (!this.validateCurrentStep()) {
          this.scrollTop();
          return;
        }
        this.select(this.index + 1);
        view.triggerMethod('save');
      }
    },

    validateCurrentStep: function() {
      return this.model.get('fields').at(this.index).validate();
    },

    saveClickHandler: function() {
      var view = this.getOption('rootView') || this;
      view.triggerMethod('save');
    },

    selectHandler: function(index) {
      if (!this.registered) {
        var view = this.getOption('rootView') || this;
        view.triggerMethod('register', index);
        return;
      }
      if (this.index < index && !this.validateCurrentStep()) {
        this.scrollTop();
        return;
      }
      this.select(index);
    },

    nextHandler: function(view) {
      if (this.steps.children.last() === view) {
        this.triggerMethod('next');
        return;
      }
      var index = this.model.get('fields').indexOf(view.model);
      if (index >= 0) { this.select(index + 1); }
    },

    scrollTop: function() {
      // stop scroll animation on any user action
      var stopEvents = 'scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove';
      var stop = function() {
        UIkit.$('html,body').stop();
        $('html,body').off(stopEvents, stop);
      };
      $('html,body').on(stopEvents, stop);
      UIkit.Utils.scrollToElement(this.tabs.$el, {
        complete: function() { $('html,body').off(stopEvents, stop); }
      });
    }
  });
});


Cрабатывают обработчики в файле steps.js при переходе по вкладкам. По подвкладкам нет.

Например при переходе на другую вкладку сработал обработчик из файла steps.js
selectHandler: function(view) {
      this.triggerMethod('select', this.collection.indexOf(view.model));
    },


По подвкладкам он не срабатывает
Для вкдадок и подвкладок используется одна вьюшка:

var Steps = Parent.extend({
    tagName: 'ul',
    className: 'uk-switcher special',
    defaultChild: Empty


Заранее спасибо за ответ.
  • Вопрос задан
  • 342 просмотра
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы