Javascript Durandal小部件,动态模板化部件

Javascript Durandal小部件,动态模板化部件,javascript,jquery,knockout.js,widget,durandal,Javascript,Jquery,Knockout.js,Widget,Durandal,我正在用Durandal构建一个向导小部件,我想这样使用它: <div data-bind="wizard: options"> <!-- Step 1 --> <span data-part="step-header-1"> Step 1 </span> <div data-part="step-c

我正在用Durandal构建一个向导小部件,我想这样使用它:

        <div data-bind="wizard: options">
            <!-- Step 1 -->
            <span data-part="step-header-1">
                Step 1
            </span>
            <div data-part="step-content-1">
                step content here
            </div>

            <!-- Step 2 -->
            <span data-part="step-header-2">
                Step 2
            </span>
            <div data-part="step-content-2">
                step content here
            </div>
        </div>

第一步
步骤内容在这里
步骤2
步骤内容在这里
这是实际的小部件(为简洁起见,请删节):


我已经开始工作了,使用jQuery获取数据部分,将数据部分的内部HTML分配给步骤模型上的属性,然后使用HTML绑定将内容绑定到每个步骤。这在DOM方面是可行的,但这样做意味着我的步骤内容不会被数据绑定。。我很确定这是因为我使用了html绑定,它不绑定内容


有没有一种方法可以在不将每个步骤分离到新视图的情况下使用Durandal小部件实现这一点?

正如我所怀疑的,我的绑定不适用的问题是因为我使用了
html
绑定来设置步骤内容。当Knockout设置HTML时,它不会对其应用绑定

我编写了自己的HTML绑定处理程序,它包装HTML并将其作为DOM节点插入—敲除可能会对此应用绑定

(function(window, $, ko) {
    var setHtml = function (element, valueAccessor) {
        var $elem = $(element);
        var unwrapped = ko.utils.unwrapObservable(valueAccessor());
        var $content = $(unwrapped);
        $elem.children().remove().end().append($content);
    };
    ko.bindingHandlers.htmlAsDom = {
        init: setHtml,
        update: setHtml
    };
}(window, jQuery, ko));

请注意,这仅在绑定值包装为节点(例如在div标记中)时有效。如果没有,它将不会呈现它。

正如我所怀疑的,我的绑定没有应用的问题是因为我使用了
html
绑定来设置步骤内容。当Knockout设置HTML时,它不会对其应用绑定

我编写了自己的HTML绑定处理程序,它包装HTML并将其作为DOM节点插入—敲除可能会对此应用绑定

(function(window, $, ko) {
    var setHtml = function (element, valueAccessor) {
        var $elem = $(element);
        var unwrapped = ko.utils.unwrapObservable(valueAccessor());
        var $content = $(unwrapped);
        $elem.children().remove().end().append($content);
    };
    ko.bindingHandlers.htmlAsDom = {
        init: setHtml,
        update: setHtml
    };
}(window, jQuery, ko));

请注意,这仅在绑定值包装为节点(例如在div标记中)时有效。如果没有,它将不会呈现它。

这里有一个实现,它使用传统的Durandal master/detail方法与选项卡小部件相结合。tab窗口小部件仅实现选项卡功能,而主控件控制推入其中的内容,而详细控件控制其自身的行为/布局

主人 视图模型 看法 看法 看法


  • . 欢迎使用fork。

    这里有一个实现,它使用传统的Durandal主/细节方法,并结合一个选项卡小部件。tab窗口小部件仅实现选项卡功能,而主控件控制推入其中的内容,而详细控件控制其自身的行为/布局

    主人 视图模型 看法 看法 看法
    
    

    • . 请随意使用fork。

      您想让它们同时显示,还是根据您所处的步骤进行更改?@PWKad所有这些都已经开始工作了,就像我说的,为了简洁起见,我减少了代码-唯一的问题是,我的步骤内容中的任何数据绑定都不会被绑定,因为整个内容都是使用Knockout的HTML绑定加载的,不将绑定应用到HTML的是使用该绑定呈现的。但问题是所有步骤是同时呈现的(即您使用单个对象来查看小部件内部的每个步骤),还是小部件表示过程中的每个步骤?我问这个问题的原因是,这取决于你想如何呈现你的内容(你是使用单例还是什么?)@PWKad我不确定我是否理解你的问题,但我会尝试回答:步骤由小部件容器中的数据部分标记决定。小部件本身应该只提供向导的UI体验,实际步骤中发生的任何事情都不关它的事。这个小部件只提供了用户界面和导航机制(我使用Knockout也让它更容易使用)。有时我想添加一些步骤验证挂钩,但那是以后的事了。:)@PWKad所以向导的每次使用都会包含一组初始步骤(指定为数据部分,如问题中所示),但如果能够动态添加步骤也会很酷。您希望它们都同时显示,还是根据您所处的步骤进行更改?@PWKad所有这些步骤都已在工作,正如我所说,为了简洁起见,我减少了代码——唯一的问题是我的步骤内容中的任何数据绑定都不会被绑定,因为整个内容都是使用Knockout的HTML绑定加载的,它不会将绑定应用到HTML,而是使用该绑定呈现。但关键是所有步骤都是同时呈现的(即您是使用单个对象来查看小部件内部的每个内容)还是小部件代表了过程中的每个步骤?我问的原因是它取决于您希望如何呈现内容(您是使用单例还是什么?)@PWKad我不确定我是否理解你的问题,但我会尝试回答:步骤由小部件容器中的数据部分标记决定。小部件本身应该只提供向导的UI体验,实际步骤中发生的任何事情都不关它的事。小部件只提供用户界面以及这是导航机制(我也使用Knockout来简化操作)。有时我想添加一些步骤验证挂钩,但那是以后的事了。@PWKad,因此向导的每次使用都会包含一组初始步骤(指定为数据部分,如问题所示),但是能够动态添加步骤也会很酷。你考虑过使用传统的主/细节设计吗?在上有一个关于这个概念的讨论,我在@RainerAtSpirit上创建了一个例子
      define(['./tab', 'plugins/widget', 'knockout'], function (Tab, widget, ko) {
      
          return {
              tabs: ko.observableArray([
                  new Tab('Durandal', 'A ...', true),
                  new Tab('UnityDatabinding', 'A ...'),
                  new Tab('Caliburn.Micro', 'C ...')
              ]),
              addNewTab: function() {
                  this.tabs.push(new Tab('New Tab ', 'A test tab.'));
              }
          };
      });
      
      <div>
          <h1>Tabs sample</h1>
          <!-- ko widget : {kind: 'tabs', items : tabs} -->
          <!-- /ko -->
      
          <button class="btn" data-bind="click: addNewTab">Add</button>
      </div>
      
      define(['durandal/events', 'knockout'], function(events, ko) {
          return function(name, content, isActive) {
              this.isActive = ko.observable(isActive || false);
              this.name = name;
              this.content = content;
          };
      });
      
      <div>
          <div data-bind="html: description"></div>
      </div>
      
      define(['durandal/composition', 'jquery'], function(composition, $) {
      
          var ctor = function() { };
      
          ctor.prototype.activate = function(settings) {
              this.settings = settings;
          };
      
          ctor.prototype.detached = function() {
              console.log('bootstrap/widget/viewmodel: detached', arguments, this);
          };
      
          ctor.prototype.toggle = function(model, event){
              this.deactivateAll();
              model.isActive(true);
      
          };
      
          ctor.prototype.deactivateAll = function(){
      
              $.each(this.settings.items(), function(idx, tab){
                  tab.isActive(false);
              });
          };
      
      
      
          return ctor;
      });
      
      <div class="tabs">
          <ul class="nav nav-tabs" data-bind="foreach: { data: settings.items }">
              <li data-bind="css: {active: isActive}">
                  <a data-bind="text: name, click: $parent.toggle.bind($parent)"></a>
              </li>
          </ul>
      
          <div class="tab-content" data-bind="foreach: { data: settings.items}">
              <div class="tab-pane"  data-bind="html: content, css: {active: isActive}"></div>
          </div>
      </div>