【问题标题】:Nested View collection linked to parent View Search Input链接到父视图搜索输入的嵌套视图集合
【发布时间】:2015-03-29 02:27:12
【问题描述】:

我有一个单页应用程序 (SPA),带有一个主 index.html“shell”页面,并且在这个 shell 中,当用户单击菜单时,它会将其他视图(MVC 部分视图)动态加载到“子“分区。

这些“子视图”本身有自己的视图模型并执行自己的应用绑定。这些动态“子视图”具有可淘汰的可观察数组集合。我希望当用户输入 shell viewmodels 的搜索输入时,过滤当前加载的 ViewModel 的 knockoutobservable 数组。

我在这里找到了可能类似的问题和一篇好文章 - http://www.knockmeout.net/2012/05/quick-tip-skip-binding.html - 但我觉得这个问题是一个不同的转折点,因为每次菜单点击都会动态加载一个新的视图/虚拟机,所以搜索输入需要取消 -绑定,重新绑定。

这里有一些伪代码

Index.html Shell-

<div id="shell">
  <ul id="menu" data-bind="foreach: menu">
    <li><a data-bind="text:name, attr: { href: href }, click:$root.loadView" /></li>
    <li><a data-bind="text:name, attr: { href: href }, click:$root.loadView" /></li>
  </ul>
  <input id="search" type="search" data-bind="textInput:searchWords" />

    <!-- ------------------------------------------ -->
    <!-- where sub-content is dynamically loaded to -->  
    <!-- ------------------------------------------ -->    
    <div id="sub-view" data-bind="html: subView"></div>


</div>

<script>
function shellViewModel() {
    var self = this;
    self.menu = ko.observableArray([
        { name: 'ViewA', href: "/path/to/viewA" },
        { name: 'ViewB', href: "/path/to/viewB" }
    ]);
    self.searchWords = ko.observable("");

    self.subView = ko.observable("");
    self.loadView = function(menu) {
            $.ajax({
                url: menu.href,
                success: (theView) => {
                    this.subView(theView);
                }
            });
            return false; 
        }
};

ko.applyBindings(new shellViewModel());
</script>

ViewA.html:

<div id="A">
  <ul data-bind="foreach: people">
    <li data-bind="text: name"></li>
  </ul>
</div>
<script>
function viewModelA() {
    var self = this;

    self.people = ko.observableArray([
        { name: 'Bert' },
        { name: 'Charles' },
        { name: 'Denise' }
    ]);

    // TIE self.people to shell.searchWords
};
ko.applyBindings(new viewModelA(), document.getElementById("A"));
</script>

【问题讨论】:

    标签: knockout.js


    【解决方案1】:

    作为一般规则,我始终建议不要使用多个ko.applyBindings,除非在特殊情况下。

    在这种情况下;您不需要单独应用绑定;您需要在 shellViewModel 中添加一个包含活动 ViewModel 的属性(nitpick,大写您的 VM 构造函数),例如subViewModel 匹配您当前的 subView 属性。

    您可以保持模板几乎相同,但使用 with 绑定,以便它引用 subViewModel。

    <div id="A" data-bind="with: subViewModel"> <!-- assuming no intervening layers between this and root; otherwise $root.subViewModel -->
      <ul data-bind="foreach: people">
        <li data-bind="text: name"></li>
      </ul>
    </div>
    

    至于 JS 方面;我建议你使用 requireJS 之类的东西来管理你的文件,但这并不是绝对必要的。您可以保留您的代码原样,直接嵌入到模板中,您只需要进行一些更改。

    在 index.html 中,您需要将 shell 设置为可以在其他地方引用的全局变量。 (同样,requireJS 会让你避免像这样的全局变量)所以:

    function shellViewModel () {
         //omitted
    }
    
    shellVM = new shellViewModel();
    ko.applyBindings(shellVM);
    

    然后在加载 ViewModelA 的逻辑中:

    function viewModelA() {
    
    }
    shell.subViewModel(new viewModelA());
    

    【讨论】:

    • 在我的示例中,subView 属性是来自 ajax 调用的原始 html,基本上是您在我的问题的第二个代码块中看到的所有内容。您的答案中的 html,它仍然在动态加载的单独文件中吗?你是说在 shellViewModel 中有一个属性应该是 viewmodel 实例——它在哪里被实例化?并被摧毁?
    • 是的;我误读了你的例子。但是,是的,您的 shellViewModel 中应该有一个属性来保存活动的 ViewModel,就像 subView 保存当前视图 html 一样。当你第一次加载视图时,你会想要加载它;然后你可以保留它以供重用,或者让它超出范围并在完成时收集垃圾。
    • 感谢您的回复。我仍然认为您的解决方案不适用于我的目的,但也许我很困惑..每个视图都有不同的 HTML,并且它是自己的视图模型。假设它们是 100 个视图/视图模型的菜单中的 100 个链接,它们都是不同的 - 共同因素是它们都有一个我想与 shell 中的搜索输入相关联的集合。我不能将视图放在带有“with”绑定的 index.html shell 中——它们太复杂了,而且会一团糟。视图会在哪里加载 ajax,然后绑定到它的视图模型?
    • 你有很多方法可以做到这一点。老实说,你真的应该研究一下像 requireJS 这样的东西来管理文件的异步加载;你目前正在做的事情——将你的 ViewModel 逻辑嵌入到模板中——是一种反模式。
    • 我在回答中添加了一些解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多