【问题标题】:Display "Loading" Until Data Is Displayed, Using Knockout使用 Knockout 显示“正在加载”直到显示数据
【发布时间】:2015-05-07 03:50:10
【问题描述】:

我目前正在尝试学习淘汰赛,所以请将所有答案保留在淘汰赛中。 我有一个公司 NBI 的联系人列表,在联系人列表的顶部显示“NBI 有 # 个员工”。目前我有一个超时,在 5 秒后填写初始联系人。我想要发生的是在 5 秒过去并显示员工之前不显示“ NBI Has #Employees”,id 还希望显示“Loading”来代替“NBI Has #Employees” ” 直到显示员工,然后将加载替换为“ NBI Has #Employees”。

这是一个小提琴http://jsfiddle.net/grahamwalsh/2cf8nr3t/

这是我的代码

html

<div class='NbiEmployees'> 

<h2>NBI Employees</h2>
<h3>NBI has <span data-bind="text: employees().length"></span> Employees</h3>
<div id='employeesList'>
    <table class='employeesEditor'>
        <tr>
            <th>First name</th>
            <th>Last name</th>
            <th>Phone numbers</th>
        </tr>
        <tbody data-bind="foreach: employees">
            <tr>
                <td>
                    <input data-bind='value: firstName' />
                    <div><a href='#' data-bind='click: $root.removeEmployee'>Delete</a></div>
                </td>
                <td><input data-bind='value: lastName' /></td>
                <td>
                    <table>
                        <tbody data-bind="foreach: phones">
                            <tr>
                                <td><input data-bind='value: type' /></td>
                                <td><input data-bind='value: number' /></td>
                                <td><a href='#' data-bind='click: $root.removePhone'>Delete</a></td>
                            </tr>
                        </tbody>
                    </table>
                    <a href='#' data-bind='click: $root.addPhone'>Add number</a>
                </td>
            </tr>
        </tbody>
    </table>
</div>

<p>
    <button data-bind='click: addEmployee'>Add an Employee</button>
    <button data-bind='click: save, enable: employees().length > 0'>Save to JSON</button>
</p>

<textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled='disabled'> </textarea>

CSS

body { font-family: arial; font-size: 14px; }

.NbiEmployees { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 655px; }
.NbiEmployees input { font-family: Arial; }
.NbiEmployees b { font-weight: bold; }
.NbiEmployees p { margin-top: 0.9em; margin-bottom: 0.9em; }
.NbiEmployees select[multiple] { width: 100%; height: 8em; }
.NbiEmployees h2 { margin-top: 0.4em; font-weight: bold; font-size: 1.2em; }

 .NbiEmployees TR { vertical-align: top; }
 .NbiEmployees TABLE, .NbiEmployees TD, .NbiEmployees TH { padding: 0.2em; border-width: 0; margin: 0; }
 .NbiEmployees TD A { font-size: 0.8em; text-decoration: none; }
 .NbiEmployees table.contactsEditor > tbody > TR { border-bottom: 1px solid silver; }
 .NbiEmployees td input { width: 8em; }

  li { list-style-type: disc; margin-left: 20px; }

淘汰

var EmployeesModel = function () {
var self = this;
//self.employees = ko.observableArray(ko.utils.arrayMap(employees, function (employee) {
    //return { firstName: employee.firstName, lastName:    employee.lastName, phones: ko.observableArray(employee.phones) };
//}));

self.employees = ko.observableArray(
    );


setTimeout(function () {
    var data = [
        {
            firstName: "Graham", lastName: "Walsh", phones: [
              { type: "Office", number: "(555) 121-2121" },
              { type: "Mobile", number: "(555) 123-4567" }]
        },
        {
            firstName: "Kimi", lastName: "Shirasaki", phones: [
              { type: "Office", number: "(555) 444-2222" },
              { type: "Mobile", number: "(555) 999-1212" }]
        }
    ];
    self.employees(ko.utils.arrayMap(data,function (employee) {
        return { firstName: employee.firstName, lastName: employee.lastName, phones: ko.observableArray(employee.phones) };
    }))},5000);

self.addEmployee = function () {
    self.employees.push({
        firstName: "",
        lastName: "",
        phones: ko.observableArray()
    });
};

self.removeEmployee = function (employee) {
    self.employees.remove(employee);
};

self.addPhone = function (employee) {
    employee.phones.push({
        type: "",
        number: ""
    });
};

self.removePhone = function (phone) {
    $.each(self.employees(), function () { this.phones.remove(phone) })
};

self.save = function () {
    self.lastSavedJson(JSON.stringify(ko.toJS(self.employees), null, 2));
};

self.lastSavedJson = ko.observable("")
};



$(document).ready(function () {
ko.applyBindings(new EmployeesModel());
});

【问题讨论】:

    标签: knockout.js


    【解决方案1】:

    您可以使用 loaded observable 和两个不同的模板:

    self.loaded = ko.observable(false);
    
    self.activeTemplate = ko.computed(function() {
        return self.loaded() ? 'loaded' : 'loading';
    });
    
    <div class='NbiEmployees' data-bind="template: activeTemplate"></div>
    

    完整示例:

    var EmployeesModel = function () {
        var self = this;
    
        self.employees = ko.observableArray();
    
        self.loaded = ko.observable(false);
        
        self.activeTemplate = ko.computed(function() {
            return self.loaded() ? 'loaded' : 'loading';
        });
    
        self.loadData = function loadData() {
          self.loaded(false);
            
          setTimeout(function () {
            var data = [{
                firstName: "Graham",
                lastName: "Walsh",
                phones: [{
                    type: "Office",
                    number: "(555) 121-2121"
                }, {
                    type: "Mobile",
                    number: "(555) 123-4567"
                }]
            }, {
                firstName: "Kimi",
                lastName: "Shirasaki",
                phones: [{
                    type: "Office",
                    number: "(555) 444-2222"
                }, {
                    type: "Mobile",
                    number: "(555) 999-1212"
                }]
            }];
            self.employees(ko.utils.arrayMap(data, function (employee) {
                return {
                    firstName: employee.firstName,
                    lastName: employee.lastName,
                    phones: ko.observableArray(employee.phones)
                };
            }));
              
            self.loaded(true);
         }, 5000);
            
        };
    
        self.addEmployee = function () {
            self.employees.push({
                firstName: "",
                lastName: "",
                phones: ko.observableArray()
            });
        };
    
        self.removeEmployee = function (employee) {
            self.employees.remove(employee);
        };
    
        self.addPhone = function (employee) {
            employee.phones.push({
                type: "",
                number: ""
            });
        };
    
        self.removePhone = function (phone) {
            $.each(self.employees(), function () {
                this.phones.remove(phone)
            })
        };
    
        self.save = function () {
            self.lastSavedJson(JSON.stringify(ko.toJS(self.employees), null, 2));
        };
    
        self.lastSavedJson = ko.observable("")
        self.loadData();
    };
    
    
    ko.applyBindings(new EmployeesModel());
    body {
        font-family: arial;
        font-size: 14px;
    }
    .NbiEmployees {
        padding: 1em;
        background-color: #EEEEDD;
        border: 1px solid #CCC;
        max-width: 655px;
    }
    .NbiEmployees input {
        font-family: Arial;
    }
    .NbiEmployees b {
        font-weight: bold;
    }
    .NbiEmployees p {
        margin-top: 0.9em;
        margin-bottom: 0.9em;
    }
    .NbiEmployees select[multiple] {
        width: 100%;
        height: 8em;
    }
    .NbiEmployees h2 {
        margin-top: 0.4em;
        font-weight: bold;
        font-size: 1.2em;
    }
    .NbiEmployees TR {
        vertical-align: top;
    }
    .NbiEmployees TABLE, .NbiEmployees TD, .NbiEmployees TH {
        padding: 0.2em;
        border-width: 0;
        margin: 0;
    }
    .NbiEmployees TD A {
        font-size: 0.8em;
        text-decoration: none;
    }
    .NbiEmployees table.contactsEditor > tbody > TR {
        border-bottom: 1px solid silver;
    }
    .NbiEmployees td input {
        width: 8em;
    }
    li {
        list-style-type: disc;
        margin-left: 20px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    
    <div class='NbiEmployees' data-bind="template: activeTemplate"></div>
    
    <script id="loading" type="text/html">
      <p>Loading, please wait</p>
    </script>
    
    <script id="loaded" type="text/html">
      <h2>NBI Employees</h2>
      <h3>NBI has <span data-bind="text: employees().length"></span> Employees</h3>
    
      <div id='employeesList'>
        <table class='employeesEditor'>
          <tr>
            <th>First name</th>
            <th>Last name</th>
            <th>Phone numbers</th>
          </tr>
          <tbody data-bind="foreach: employees">
            <tr>
              <td>
                <input data-bind='value: firstName' />
                <div><a href='#' data-bind='click: $root.removeEmployee'>Delete</a>
                </div>
              </td>
              <td>
                <input data-bind='value: lastName' />
              </td>
              <td>
                
                <table>
                  <tbody data-bind="foreach: phones">
                    <tr>
                      <td>
                        <input data-bind='value: type' />
                      </td>
                      <td>
                        <input data-bind='value: number' />
                      </td>
                      <td><a href='#' data-bind='click: $root.removePhone'>Delete</a>
                      </td>
                    </tr>
                  </tbody>
                </table>
                
                <a href='#' data-bind='click: $root.addPhone'>Add number</a>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
      <p>
        <button data-bind='click: addEmployee'>Add an Employee</button>
        <button data-bind='click: save, enable: employees().length > 0'>Save to JSON</button>
      </p>
      <textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled='disabled'></textarea>
    </script>

    【讨论】:

      【解决方案2】:

      我喜欢为此做的一个技巧基本上是让普通样式标签隐藏真实内容,然后使用数据绑定使内容 div 可见并在应用绑定时隐藏加载内容。

      <div id="realcontent" style="display:none"  data-bind="visible:true">
      Content!
      </div>
      <div id="loadingdisplay" data=bind="visible:false">
       Loading display!
      </div>
      

      然后,在我的 viewModels 中,我总是有一个 Load(),我在其中执行所有长时间运行的数据加载/处理,并且我的全局 js 中有一个片段可以执行实际加载。因此,通过这种方式,我的视图模型中没有任何与这种可见切换有关的明确内容,我也没有在 dom 中实际移动事物的处理,它只是切换可见性。这个 Load 函数还允许我在应用绑定之前进行任何我需要做的设置(比如设置计算的 observables)

      viewModel.Load();
      ko.applyBindings(viewModel);
      

      现在这些东西主要用于初始加载,如果它是在页面初始加载后触发的,那么你可以用普通的 observables 做同样的想法 ala

      <div id="realcontent" data-bind="visible:LoadingDone">
      Content!
      </div>
      <div id="loadingdisplay" data=bind="visible:!LoadingDone()">
       Loading display!
      </div>
      

      然后当你开始加载时

      LoadingDone(false)
      

      当它完成时
      LoadingDone(true)

      即使有很多元素,这些东西的性能也非常好,因为你实际上并没有改变 dom。

      【讨论】:

        【解决方案3】:

        在您的视图模型中,您可以添加自己的计算属性“isLoaded”或类似的属性(例如self.isLoaded = ko.observable(false);,然后将包含“NBI 有 X 名员工”的元素的数据绑定设置为 data-bind="enabled: isLoaded"。这样元素在 isLoaded 设置为 true 之前不会显示。

        <div data-bind="enabled: isLoaded">NBI has <span data-bind='employees().length'></span> employees</div>
        
        self.isLoaded = ko.observable(false);
        

        我想,如果 isLoaded = false,您也可以只放置一个模态 DIV(如 jQuery 对话框),这将是您的“正在加载”屏幕。或者只是用“正在加载”的 DIV 替换您的整个内容,加载 DIV 在isLoaded==false 上可见,内容容器在isLoaded==true 上可见。这样,如果内容尚未加载/未准备好,您将获得“正在加载...”,以及实际的视图模型。

        只是一些想法。

        【讨论】:

          猜你喜欢
          • 2013-04-16
          • 2016-03-23
          • 1970-01-01
          • 1970-01-01
          • 2020-02-01
          • 1970-01-01
          • 2016-07-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多