使用Knockout显示“加载”直到显示数据

时间:2015-03-05 17:05:29

标签: knockout.js

我目前正在尝试学习淘汰赛,所以请保留所有答案。 我有一个公司NBI的联系人列表,在联系人列表的顶部显示" NBI有#员工"。目前我有一个超时,在5秒后填写初始联系人。我希望发生的是拥有" NBI有#员工"直到5秒过去并且显示员工才显示,id也希望"正在加载"显示代替" NBI有#员工"直到员工显示然后加载替换为" NBI有#员工"。

这是一个小提琴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());
});

3 个答案:

答案 0 :(得分:1)

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

self.loaded = ko.observable(false);

self.activeTemplate = ko.computed(function() {
    return self.loaded() ? 'loaded' : 'loading';
});

<div class='NbiEmployees' data-bind="template: activeTemplate"></div>

完整示例:

&#13;
&#13;
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());
&#13;
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;
}
&#13;
<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>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

我喜欢为此做的一个技巧基本上是普通样式标签隐藏真实内容然后数据绑定将使内容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中处理实际移动的东西它只是切换可见性。这个加载函数还允许我在应用绑定之前进行任何我需要做的设置(比如设置计算的可观察量)

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。

答案 2 :(得分:0)

在您的viewmodel中,您可以添加自己的计算属性&#34; isLoaded&#34;或某些此类(如self.isLoaded = ko.observable(false);,然后为持有&#34; NBI有X名员工的元素设置数据绑定&#34;为data-bind="enabled: isLoaded"。这样,元素就会赢得&#39; t显示,直到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对话框),这将是你的&#34; Loading&#34;屏幕。或者只需用&#34; loading&#34;替换您的整个内容。 DIV和加载DIV在isLoaded==false上是可见的,内容容器可以isLoaded==true查看。通过这种方式,你得到了#34;正在加载......&#34;如果内容尚未加载/未准备好,则实际的viewmodel为。

只是一些想法。