模型更改时视图中的列表不会更新

Posted

技术标签:

【中文标题】模型更改时视图中的列表不会更新【英文标题】:list in View does not update when the Model changes 【发布时间】:2018-03-31 12:19:55 【问题描述】:

我正在尝试使用 knockout.js 构建 MVVM。这个想法是 $(document).ready(function() ... 中的脚本添加了一个新项目 model.addElement("value"); -每 3 秒向模型添加一次“值”,并且应该以 html 格式显示。尽管在控制台输出中您可以看到模型正在更改并且元素被推送到 items 列表,但 HTML 保持不变。

同时,如果我取消注释 self.items.push($('#new_item').val()); 行 - 每次添加元素时 HTML 页面都会发生变化到模型。

请帮助我理解我做错了什么,为什么我不能通过 model.addElement("value"); 行传递这个“值”字符串?

// Overall viewmodel for this screen, along with initial state
var ListsViewModel = function(item) 
  var self = this;
  self.item = item;

  self.items = ko.observableArray(["First", "Second", "Third"]);

  self.addElement = function(item) 
    self.items().push(item);
    //self.items.push($('#new_item').val()); //--> uncomment for adding element with a button click
  

;
var model = new ListsViewModel()
ko.applyBindings(model, document.getElementById("one"));

$(document).ready(function() 
  //comment this if you want add elements only when you click on button
  setInterval(function() 
    model.addElement("value");
    console.log(model.items());
  , 3000);
);
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

  <title>Updating list to the server (automatically)</title>

</head>

<body>
  <div id="one">
    <h1>Records:</h1>

    <div class="list-group" data-bind="foreach: items">
      <a href="#" class="list-group-item" data-bind="text: $data"></a>
    </div>

    <div class="form-group">
      <label for="new_item">Item name:</label>
      <input type="text" class="form-control" id="new_item">
    </div>

    <form>
      <input type="button" class="btn btn-info" value="Add element" data-bind="click: addElement">
    </form>
  </div>
</body>
<script src="static/js/viewModel.js"></script>
<script src="static/js/main.js"></script>

</html>

统一更新: 也许我说不清楚,我想要的是每 3 秒向模型添加一次新值,并且此更改显示在视图 (HTML) 中。 正如@user3297291 所建议的那样,我实现了将 self.items().push(item); 更改为 self.items.push(item);。 这是代码的最终版本,完全符合我的要求:

// Overall viewmodel for this screen, along with initial state
var ListsViewModel = function() 
  var self = this;

  self.items = ko.observableArray(["First", "Second", "Third"]);
  //self.item = ko.observable("");

  self.addElement = function(item) 
    self.items.push(item);
  

;
var model = new ListsViewModel()
ko.applyBindings(model, document.getElementById("one"));

$(document).ready(function() 
  //comment this if you want add elements only when you click on button
  setInterval(function() 
    model.addElement("value");
    console.log(model.items());
  , 3000);
);
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

  <title>Updating list to the server (automatically)</title>


</head>

<body>
  <div id="one">
    <h1>Records:</h1>

    <div class="list-group" data-bind="foreach: items">
      <a href="#" class="list-group-item" data-bind="text: $data"></a>
    </div>
  </div>
</body>
<script src="static/js/viewModel.js"></script>
<script src="static/js/main.js"></script>

</html>

【问题讨论】:

【参考方案1】:

一些使您的 sn-p 正常工作的小错误修复:

不要推送到数组inside self.items,因为敲除将无法注意到它的内容发生了变化。直接推送到observableArrayself.items.push 而不是self.items().push 使self.item 可观察,以便您可以将其值绑定到文本输入:self.item = ko.observable("") 使用value绑定同步self.item&lt;input/&gt;.value:&lt;input data-bind="value: item"&gt; addElement 不接收项目,它接收事件和当前绑定上下文。相反,您可以使用 self.item() 检索文本框的值,推送它,然后使用 self.item("") 清除它

使用淘汰赛时,您将规则设置为不以任何其他方式接触 DOM,除非通过淘汰赛绑定。每当您使用 jQuery 设置或检索值时,您应该问的第一个问题是“我可以使用什么淘汰绑定”。

固定版本:

// Overall viewmodel for this screen, along with initial state
var ListsViewModel = function(item) 
  var self = this;
  self.item = ko.observable("");

  self.items = ko.observableArray(["First", "Second", "Third"]);

  self.addElement = function() 
    self.items.push(self.item());
    self.item("");
  

;
var model = new ListsViewModel()
ko.applyBindings(model, document.getElementById("one"));
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

  <title>Updating list to the server (automatically)</title>

</head>

<body>
  <div id="one">
    <h1>Records:</h1>

    <div class="list-group" data-bind="foreach: items">
      <a href="#" class="list-group-item" data-bind="text: $data"></a>
    </div>

    <div class="form-group">
      <label for="new_item">Item name:</label>
      <input type="text" class="form-control" id="new_item" data-bind="value: item">
    </div>

    <form>
      <input type="button" class="btn btn-info" value="Add element" data-bind="click: addElement">
    </form>
  </div>
</body>
<script src="static/js/viewModel.js"></script>
<script src="static/js/main.js"></script>

</html>

【讨论】:

请问你这个“显示代码sn-p”是怎么做到的? 编辑 sn-p 时,左侧有一个“默认隐藏 sn-p”复选框,您可以勾选。此复选框设置也包含在您帖子中插入的标记标题中:hide: true(默认值为false

以上是关于模型更改时视图中的列表不会更新的主要内容,如果未能解决你的问题,请参考以下文章

数据库更改时,Android SimpleCursorAdapter 不会更新

当视图模型@Published 更改时,SwiftUI 列表因“NSRangeException”而崩溃

当被模态视图控制器覆盖时,iOS 6 视图控制器布局在方向更改后不会更新

AngularJS 中的模型更新时视图不会更新

单击收藏夹按钮时更新列表视图

可观察对象模型在模型更新时不会更改视图值