2016-11-10 134 views
0

我從使用Grunt作爲構建工具切換到Webpack。過渡是相對平穩。至少直到我注意到我遇到以下問題。子視圖更改事件未觸發

我目前在我的應用程序中有許多Backbone視圖,並且在我移動時使用工廠方法實例化和垃圾收集。通過我的子視圖change將我的項目轉換爲Webpack後,事件不再發射(也就是說,它之前正在發射,所以我知道它在某個時刻起作用)。

for (var i=0; i<this.dayIds.length; i++) { 
    this.timeSelectorDayViews[i] = new timeSelectorDay({ 
    el: '#timePickersWrapper', 
    data: { 
     time: this.model.get(this.dayIds[i]), 
     date: moment(this.model.get('weekStartDate')).add(i, 'd') 
    } 
    }).render(); 
} 

而這裏的子視圖代碼:

'use strict'; 

import { app } from '../app'; 

export const timeSelectorDay = Backbone.View.extend({ 
    initialize: function(data) { 
     this.options = data; 
     this.options.data.formattedDate = moment(this.options.data.date).format('YYYY-MM-DD'); 
     this.events = _.clone(this.events) || {}; 
     var inputEventKey = 'change' + ' .input-' + this.options.data.formattedDate; 
     this.events[inputEventKey] = 'inputCheck'; 
     this.totalHours = 0; 
    }, 
    render: function(){ 
     this.template = _.template(app.createTemplate('templates/timeSelectorDay.tpl', this.options.data)); 
     $(this.options.el).append(this.template({})); 
     this.delegateEvents(); 
     this.checkTotalTime(); 
     return this; 
    }, 
    inputCheck: function() { 
     ... 
     ... //Doing some computational logic here 
     ... 
     app.event_bus.trigger('totalTime'); 
     app.event_bus.trigger('inputChange'); 
    }, 
    checkTotalTime: function(){ 
     var totalTimeDiv = document.getElementById('totalHours-'+this.options.data.formattedDate); 
     var totalTime = parseFloat(totalTimeDiv.innerHTML); 
     if (totalTime>0) { 
     totalTimeDiv.style.backgroundColor = '#69a776'; 
     } else { 
     totalTimeDiv.style.backgroundColor = '#dd3c3c'; 
     } 
     this.totalHours = totalTime; 
    } 
}); 

它也可能是值得注意的是我生成的事件,當用戶進入父視圖在for循環中的子視圖生成以非正常的主幹方式通過字符串連接並更改事件數組。這是因爲我需要爲我的HTML元素指定唯一的ID。

我的第一個想法是,可能由於某些原因,新的webpack實現沒有正確連接事件。我試圖通過調用this.delegateEvents()來解決這個問題,但沒有成功。

我的下一個想法是,可能事件不在視圖範圍內,或者以某種方式分離,因此我確認input元素在視圖中可附加事件。也不是問題。

我認爲什麼是最令人費解的這個情況是,如果我改變change事件到click事件它工作完全正常,並觸發相應的功能:

var inputEventKey = 'click' + ' .input-' + this.options.data.formattedDate; 

UPDATE(其他數據):

子視圖模板:

<div id="timeselectors-<%= formattedDate%>" class="row small-collapse medium-uncollapse margin-bottom border"> 
    <div class="small-12 columns"><%= moment(date).format('dddd') %> (<%= moment(date).format('MM/DD/YYYY') %>)</div> 
    <div class="small-10 columns"> 
    <div class="row small-collapse"> 
     <div class="small-5 medium-2 columns morning"> 
     <input id="morning-login" class="input-<%= formattedDate%>" type="text" id="example" placeholder="Login"/> 
     </div> 
     <div class="small-1 medium-1 columns morning dash"> - </div> 
     <div class="small-5 medium-2 columns morning"> 
     <input id="morning-logout" class="input-<%= formattedDate%>" type="text" id="example" placeholder="Logout"/> 
     </div> 
     <div class="small-5 medium-2 medium-offset-1 columns afternoon"> 
     <input id="afternoon-login" class="input-<%= formattedDate%>" type="text" id="example" placeholder="Login"/> 
     </div> 
     <div class="small-1 medium-1 columns afternoon dash"> - </div> 
     <div class="small-5 medium-2 columns afternoon end"> 
     <input id="afternoon-logout" class="input-<%= formattedDate%>" type="text" id="example" placeholder="Logout"/> 
     </div> 
    </div> 
    </div> 
    <div id="totalHours-<%= formattedDate%>" class="small-2 columns hours"> 
    <%= time %> 
    </div> 
</div> 

至於我使用一飲而盡作爲我的WebPack驅動我的WebPack配置,但這裏的配置我通入的WebPack實例:

{ 
    entry: './src/app/client-app/index.js', 
    output: { 
    path: path.join(__dirname, 'dist/app/js'), 
    filename: 'app.bundle.js' 
    }, 
    plugins: [ 
    new webpack.ProvidePlugin({ 
     '_': 'lodash' 
    }) 
    ], 
    module: { 
    loaders: [ 
     {test: /\.js$/, exclude: /node_modules/, loaders: ['babel'] }, 
    ] 
    } 
} 

的WebPack項文件:

// import 'babel-polyfill'; 
import 'script!jquery'; 
import 'script!lodash'; 
// import 'script!what-input'; 
import Backbone from 'backbone'; 
import 'backbone-validation'; 
import 'script!jquery.cookie'; 
import 'script!moment'; 
import 'script!fastclick'; 
import 'script!clndr'; 
import 'script!timepicker'; 
import 'script!foundation-sites/js/foundation'; 

import { app } from './app'; 

$(document).ready(function() { 
    app.init(); 

    //Initialize Foundation 
    $(document).foundation(); 
}); 

除了所有,如果你想克隆下來我應該提到,所有的代碼在GitHub上公開獲得回購並重現該問題:

https://github.com/wootencl/timeSheetApplication/tree/ProjectRewrite

UPDATE(16年11月14日):經過unsuccesfully試圖將CONTRO內複製該(plunkr等)我決定開始慢慢地向後工作來診斷問題。到目前爲止,我發現這個問題不是來自webpack,而是來自我項目的模塊化。我從每個文件的快速腳本標記轉到根目錄index.js並導入了所有依賴模塊,這似乎是事情開始出錯的地方。

+0

沒有模板和/或webpack配置或[mcve],不可能發現問題。 –

+1

感謝您的快速回復@EmileBergeron!要更改我的文件以反映您的建議並回報。 – wootencl

回答

1

雖然我無法發現所提供的代碼的問題,但我可以開始指出一些可以改進的地方。

首先,我會直接傳遞自定義選項,不需要嵌套的data對象。

this.timeSelectorDayViews[i] = new timeSelectorDay({ 
    el: '#timePickersWrapper', 
    time: this.model.get(this.dayIds[i]), 
    date: moment(this.model.get('weekStartDate')).add(i, 'd') 
}).render(); 

然後在子的看法,我會移動events變成構造,前骨幹創建調用setElement與所提供的el

export const timeSelectorDay = Backbone.View.extend({ 
    // The template should be compiled once here, then used in the render function. 
    template: _.template(app.createTemplate('templates/timeSelectorDay.tpl')), 

    constructor: function(options) { 
     this.options = _.extend({ 
      /* default options could go here */ 
     }, options); // make a copy and use it. 
     this.options.formattedDate = moment(this.options.date).format('YYYY-MM-DD'); 

     // change the events hash before delegating the events. 
     // the constructor is a good place for this. 
     this.events['change .input-' + this.options.formattedDate] = 'inputCheck'; 

     Backbone.View.prototype.constructor.apply(this, arguments); 
    }, 

    initialize: function(options) { 
     this.totalHours = 0; 
    }, 
    render: function() { 
     // use the $el directly, avoid global jQuery. 
     this.$el.html(this.template(this.options)); 
     this.checkTotalTime(); 
     return this; 
    }, 
    inputCheck: function() { 
     // Doing some computational logic here 
     // ...snip... 
     app.event_bus.trigger('totalTime'); 
     app.event_bus.trigger('inputChange'); 
    }, 
    checkTotalTime: function() { 
     // use Backbone's jQuery shortcut instead of the Javascript native 
     // api, it's easier and it is scoped to the view's el. 
     var totalTimeDiv = this.$('#totalHours-' + this.options.formattedDate), 
      totalTime = parseFloat(totalTimeDiv.html()); 
     // I would avoid changing the css in favor of toggling a class. 
     // It would keep the style separated from the logic. 
     totalTimeDiv.css('background-color', totalTime > 0 ? '#69a776' : '#dd3c3c'); 
     this.totalHours = totalTime; 
    } 
}); 
+1

這種方式仍然不幸運。雖然我認爲你對清理我的觀點的建議有希望讓我指出正確的方向。將在今晚/明天晚些時候報告我的調查結果。再次感謝您的幫助! – wootencl

+1

@wootencl很高興幫助;)另一個問題,它真的與webpack有關嗎?如果只採用相關的視圖/模板並創建最小的可運行片段,會怎麼樣? –

+1

好問題。我認爲它是webpack,因爲當我從Grunt遷移到webpack時,我開始注意到這個問題,儘管可能並非如此。如果我今晚無法弄清楚,我可能會嘗試創建一個plunkr(或類似的東西),看看我是否可以重新創建這個問題。 – wootencl