2016-07-27 5 views
3

Я честно не знаю, почему это не работает. Кажется, это довольно стандартная операция. Он не устанавливает компонент, не выдает ошибку и не запускает функцию сразу после нее. Все happing в cfg.AddToCart.vm.addToCart()Монтаж не работает внутри контроллера vm

cfg.AddToCart = { 
    vm: { 
    init() { 
     return; 
    }, 

    addToCart() { 
     let parent = document.getElementById('atc-error'); 
     let errEl = document.getElementById('atc-error-component'); 

     if(cfg.state.selections.SIZE) { 
      m.mount(errEl, null); 
     } else { 
      let component = new cfg.selectComponent(cfg.Options, cfg.optionsView); 
      m.mount(errEl, component); 

      cfg.util.toggleSlide(parent); 
     } 
    } 
    }, 

    controller() { 
    cfg.AddToCart.vm.init(); 
    } 
}; 

cfg.AddToCart.view = function() { 
    return <div id="add-to-cart-container"> 
    <div id="atc-error"> 
     <span>Select a size and add to cart again.</span> 
     <div id="atc-error-component"></div> 
    </div> 
    <div class="small-12 columns"> 
     <button class="large button alert" 
      onclick={() => { 
       this.vm.addToCart(); 
      }}> 
      Add To Cart 
     </button> 
    </div> 
    </div>; 
}; 

Мы используем new cfg.selectComponent(cfg.Options, cfg.optionsView) компонент несколько раз в течение приложения, так что это не ошибка с этим. #atc-error установлен в display:none, но это также не проблема. Это не единственное условное монтирование в приложении, поэтому я немного в тупике.

ответ

3

от глядя на то, как вы структурированном код это ударяет меня вам не хватает на много преимуществ MITHRIL в. В частности:

  1. Если ваш «vm» неотличим от контроллера, вам не нужно создавать и управлять целым отдельным объектом для этого. Особенно, когда вы используете методы для управления состоянием локального компонента, является заданием контроллера. Контроллер предоставляет объект для представления - это следует рассматривать как «vm». Наличие отдельного объекта для хранения состояния модели полезно, когда состояние релевантно вне экземпляра компонента: у вас уже есть это в вашем cfg.state, поэтому в этом случае vm является избыточным.
  2. Мифриловые виды имеют метод config, который предоставляет реальный элемент DOM после каждой ничьей. Вам не нужно хранить ссылки на элементы представления, так как вы можете сделать это здесь. Это значительная часть того, что делает виртуальные библиотеки DOM настолько привлекательными: взгляд является умным, и вы можете вводить в них специфическую для представления логику.
  3. Компоненты могут быть вызваны непосредственно из представления, и представление может использовать условную логику, чтобы определить, следует ли их называть. m.mount необходимо только для инициализации приложения Mithril и определения компонентов верхнего уровня; из кода Мифрила вы можете напрямую вызвать вложенные компоненты через функцию m.

Несколько других недоразумений:

  1. Контроллер выполняет до того визуализируется вид (и когда он выполняется, свойство инициализирует подвержено вашу функцию вида в качестве первого аргумента), поэтому вы не можете получить доступ к элементам, созданным представлением при инициализации контроллера.
  2. Функция init в vm не имеет никакой цели.

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

// Determine what your external dependencies are 
const { state, selectComponent } = cfg 

// Define the component 
const AddToCart = { 
    // No need for a separate VM: it is identical in purpose & function to the controller 
    controller : function(){ 
    // No need to store element references in the model: those are the view's concern. 
    // Keep the VM/ctrl size to a minimum by only using it to deal with state 
    this.addToCart =() => { 
     if(state.selections.SIZE) 
     this.showSize = false 

     else { 
     this.showSize = true 

     this.slideToErr = true 
     } 
    } 
    }, 

    view : ctrl => 
    m('#add-to-cart-container', 
     m('#atc-error', { 
     // Config exposes the element and runs after every draw. 
     config : el => { 
      // Observe state, and affect the view accordingly: 
      if(ctrl.slideToErr){ 
      el.scrollIntoView() 

      // Reset the state flag 
      ctrl.slideToErr = false 
      } 
     } 
     }, 
     m('span', 'Select a size and add to cart again.'), 

     // This is an and condition, ie 'if A, then B 
      ctrl.showSize 
      // This is how you invoke a component from within a view 
     && m(selectComponent) 
    ), 

     m('.small-12 columns', 
     m('button.large button alert', { 
      onclick :() => 
      ctrl.addToCart(); 
     }, 
      'Add To Cart' 
     ) 
    ) 
    ) 
} 
+0

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

0

Работал, изменив его на эту схему:

cfg.AddToCart = { 
    vm: { 
    init() { 
     this.errorComponent = m.prop(); 
    }, 

    addToCart() { 
     let parent = document.getElementById('atc-error'); 
     let errEl = document.getElementById('atc-error-component'); 

     if(cfg.state.selections.SIZE) { 
      cfg.util.toggleSlide(parent); 
      setTimeout(() => { 
       this.errorComponent(null); 
      }, 400); 
     } else { 
      let component = new cfg.selectComponent(cfg.Options, cfg.optionsView); 
      this.errorComponent(component); 

      setTimeout(() => { 
       cfg.util.toggleSlide(parent); 
      }, 100); 
     } 
    } 
    }, 

    controller() { 
    cfg.AddToCart.vm.init(); 
    } 
}; 

cfg.AddToCart.view = function() { 
    return <div id="add-to-cart-container"> 
    <div id="atc-error"> 
     <span>Select a size and add to cart again.</span> 
     <div id="atc-error-component" class="row"> 
      {this.vm.errorComponent() ? m.component(this.vm.errorComponent()) : ''} 
     </div> 
    </div> 
    <div class="small-12 columns"> 
     <button class="large button alert" 
      onclick={() => { 
       this.vm.addToCart(); 
      }}> 
      Add To Cart 
     </button> 
    </div> 
    </div>; 
};