【问题标题】:Require.js Backbone loading view issueRequire.js Backbone 加载视图问题
【发布时间】:2015-02-07 20:46:44
【问题描述】:

我有一个主干项目,我正在将其转换为 require.js,以便我可以学习如何使用它。我的骨干项目在转换之前运行良好。我已经完成并将项目转换为使用 require.js,但这样做时,我从 app.js 加载到视图中的静态数据不可见。此外,我无法显示从 index.html 上的表单添加的任何新数据。

有些东西阻止了视图的显示。我在 Chrome 控制台中的 app.js 文件的第 17 行不断收到错误“未捕获的类型错误:未定义不是函数”。以下是我的文件。我很确定我在概念上遗漏了一些东西,任何帮助我理解为什么我没有让它工作的输入将不胜感激。


index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>Inventory App</title>

    <link rel="stylesheet" href="assets/less/style.css">
</head>
<body>
  <div id="items">
    <form class="item_form" id="addItem" action="#" name="item_form">
      <div>
          <ul>
            <li>
                 <h2>Inventory App</h2>
                 <span class="required_notification">* Denotes Required Field</span>
            </li>
            <li>
                <label for="component">Component:</label>
                <input type="text" name="component" id="component"placeholder="Component" required/>
            </li>
            <li>
                <label for="stockQty">Stock Qty:</label>
                <input type="number" name="stockQty" id="stockQty"placeholder="Stock Qty" required/>
            </li>
            <li>
                <label for="reorderQty">Reorder #:</label>
                <input type="number" number="reorderQty" id="reorderQty" placeholder="Reorder #" required/>
            </li>
            <li>
                <label for="qtyPerCrane">Qty per Crane:</label>
                <input type="number" name="qtyPerCrane" id="qtyPerCrane" placeholder="Qty per Crane" required/>
            </li>
            <li>
                <label for="vendorId">Vendor Id:</label>
                <input type="number" name="vendorID" id="vendorID" placeholder="Vendor ID" required/>
            </li>
            <li>
               <button class="submit" id="add" >Add</button>
            </li>
          </ul>
        </div>
      </form>

<!-- Label Html goes here-->
      <table id="inventory-grid">
        <thead>
          <tr>
            <th>Component</th>
            <th>Stock Qty</th>
            <th>Qty Per Crane</th>
            <th>Reorder Qty</th>
            <th>Vendor ID</th>
            <th>&nbsp;</th>
          </tr>
        </thead>
        <tbody id="inventory-holder"></tbody>
      </table>
  </div>

<!-- render inventory items-->
  <script id="inventoryTemplate" type="text/template">
      <td>  <%= component %>                                </td>
      <td>  <%= stockQty %>                                 </td>
      <td>  <%= qtyPerCrane %>                              </td>
      <td>  <%= reorderQty %>                               </td>
      <td>  <%= vendorID %>                                 </td>
      <td>  <button class="delete">Delete</button>          </td>
 </script>

  <script data-main='js/main' src="js/lib/require.js"></script>

</body>
</html>

main.js

//configure RequireJS 
requirejs.config({
    paths: {
        jquery: 'lib/jquery',
        backbone: 'lib/backbone',
        localStorage: 'lib/backbone.localStorage',
        underscore: 'lib/underscore',
        views: 'views',
        models: 'models',
        collections: 'collections'

    }, 

      // Shim declaration
    'shim': {
        'underscore': {
          'exports': '_'
        },
        'backbone': {
          'deps': ['jquery', 'underscore'],
          'exports': 'Backbone'
        }
    }
});

// call app.js to load static data 
define(['app'], function(AppView) {

var AppView = new AppView();

});

app.js

// load view with data
define (['jquery', 'backbone'], function($,Backbone) {

    var app = app || {};

    $(function() {
        var inventory = [
            { component: 'bottom bracket', stockQty: '22', reorderQty: '15', qtyPerCrane: '13', vendorID: 'Foster Machine' },
            { component: 'bottom bracket', stockQty: '22', reorderQty: '15', qtyPerCrane: '13', vendorID: 'Foster Machine' },
            { component: 'bottom bracket', stockQty: '22', reorderQty: '15', qtyPerCrane: '13', vendorID: 'Foster Machine' },
            { component: 'bottom bracket', stockQty: '22', reorderQty: '15', qtyPerCrane: '13', vendorID: 'Foster Machine' },
            { component: 'bottom bracket', stockQty: '22', reorderQty: '15', qtyPerCrane: '13', vendorID: 'Foster Machine' }
        ];

        console.log('inventory loaded');

       // THIS IS WHERE THE ERROR GETS THROWN
        new app.InventoryView( inventory );
    });
}); 

item.js(浏览量)

// site/js/views/item.js

define(['jquery', 'backbone'], function($, Backbone) {

    var app = app || {};

    app.ItemView = Backbone.View.extend({
        tagName: 'tr',
        className: 'itemContainer',
        template: _.template( $( '#inventoryTemplate' ).html() ),

        events: {
        'click .delete': 'deleteItem'
        },

        deleteItem: function() {
            //Delete model
            this.model.destroy();

            //Delete view
            this.remove();
        },

        render: function() {
            //this.el is what we defined in tagName. use $el to get access to jQuery html() function
            this.$el.html( this.template( this.model.attributes ) );

            return this;
        }
    });

});

inventory.js(视图)

// site/js/views/inventory.js

define(['jquery', 'backbone'], function($, Backbone) {

    var app = app || {};

    app.InventoryView = Backbone.View.extend({
        el: '#items',

        initialize: function( initialInventory ) {
            this.collection = new app.Inventory( initialInventory );
            this.listenTo( this.collection, 'add', this.renderItem );
            this.render();
        },
        events:{
        'click #add':'addItem'
        },

        addItem: function( e ) {
            e.preventDefault();

            var formData = {};

            $( '#addItem li' ).children( 'input' ).each( function( i, el ) {
                if( $( el ).val() != '' )
                {
                    formData[ el.id ] = $( el ).val();
                }
            });

            this.collection.add( new app.Item( formData ) );
        },

        // render inventory by rendering each book in its collection
        render: function() {
            this.collection.each(function( item ) {
                this.renderItem( item );
            }, this );
        },

        // render an item by creating an ItemView and appending the
        // element it renders to the inventory's element
        renderItem: function( item ) {
            var itemView = new app.ItemView({
                model: item
            });
            this.$el.find('#inventory-holder').append( itemView.render().el );
        }
    });

});

item.js(模型)

// site/js/models/item.js

define(['jquery', 'backbone'], function($, Backbone) {

    var app = app || {};

    app.Item = Backbone.Model.extend({
        defaults: {
            component: 'no component',
            stockQty: 'no stock qty',
            reorderQty: 'no reorder qty',
            qtyPerCrane: 'qty per crane',
            vendorID: 'vendor ID'
        }
    });

});

inventory.js(集合)

// site/js/collections/inventory.js

define(['jquery', 'backbone'], function($, Backbone) {

    var app = app || {};

    app.Inventory = Backbone.Collection.extend({
        model: app.Item
    });

});

【问题讨论】:

  • 错误指向的代码行是什么?如果你展开错误,你看到调用堆栈了吗?如果点击错误右侧的文件链接,是否会跳转到代码中的错误位置?

标签: backbone.js model-view-controller requirejs


【解决方案1】:

我建议你研究一个示例主干/requirejs 应用程序,来感受一下,我推荐这个优秀的项目:https://github.com/BenjaminAdams/RedditJS/blob/master/public/js/app/App.js

所以你定义你的应用程序的方式是:

// app.js
define(["jquery", "backbone"], function($, Backbone) {
  // not exactly this but similar define your app here.  
  // get rid of all of this: `var app = app || {};`
  var App = new Backbone.application();

  // don't forget to return the Backbone App.
  return App;
});

定义主干视图:

// sampleView.js
define(["App", "backbone", "hbs!template/comment"], function(App, Backbone, commentTmpl) {
  // Use the variable App safely here rather than `var app = app || {};`
  return Backbone.View.extend({});
});

定义一个主干控制器:

define(["App", "backbone"], function(App, Backbone) {
  return Backbone.Controller.extend({});
});

定义一个backbone router:

define(["App", "backbone"], function(App, Backbone) {
  var AppRouter = Backbone.AppRouter.extend({});

  return AppRouter;
});

最后用 requirejs require 函数启动:例如(见here

require(["App", "router", "jquery", "backbone"], function(App, AppRouter) {
  App.appRouter = new AppRouter();
  App.start();
});

请注意,这只是一个虚拟示例,您应该了解这个想法并将其应用到您的应用程序主干方式中。

【讨论】:

  • 您可能需要补充一点,您指向的是使用 Marionette 的实现。 Backbone 上没有“应用程序”方法 - 这是 Marionette 的功能。
  • @kinakuta 我说,这只是一个虚拟示例,并以主干方式应用它。由于问题不在于如何实现主干视图等,而是关于如何使用 requirejs 构建像项目这样的主干。
  • 是的,您仍然应该提到您指向的是 Marionette 的示例,它是用于构建应用程序的特定框架。此外,您的代码给出了一个明确表示不要使用 var app = app || 的示例{} 模式,而是使用 Backbone 上实际不存在的方法。我的建议对您的帖子具有建设性。
  • 感谢您的输入 user3995789 和 @kinakuta。我尝试实施上述建议,但没有成功。我还阅读了您链接到 user3995789 的示例,但我认为添加木偶让我更加困惑。您对如何返回 'new app.InventoryView(inventory);' 的值有任何想法吗?在 app.js 中?
  • 我说,摆脱所有的应用程序。如果您需要 Inventoryview,则需要使用 requirejs 并使用传递的参数进行查看。如果你努力学习这个例子,你会解决你的问题。别指望这里有鱼。
【解决方案2】:

new app.InventoryView(inventory);会抛出错误,因为它在 app.js 中未定义。

您需要在 app.js 中加载 InventoryView.js,例如

   define (['jquery', 'backbone', 'InventoryView'], function($,Backbone,InventoryView) {

        var app = app || {};

        $(function() {
            var inventory = [
                { component: 'bottom bracket',.... },....... Your Code

            ];

            console.log('inventory loaded');
          app.InventoryView = InventoryView( inventory );

    // AND NOW YOU CAN CALL YOUR LINE
              new app.InventoryView();

        });
    }); 

在使用 RequireJS 时,您必须加载文件(确保它返回一些值)并在内联函数中引用它并使用它。

【讨论】:

    猜你喜欢
    • 2012-04-19
    • 2013-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多