KnockoutJS如何创建更简洁,更短的嵌套循环?

时间:2019-02-15 22:35:30

标签: knockout.js

我已经为一年中的每个月创建了一个嵌套循环,并将其推送到用户界面。如何使我的代码不那么冗长,并使嵌套循环更简洁?

数据来自SharePoint终结点(odata)。

逻辑是现实事件在UI中显示。它们在Observable数组中,每个都属于一年中的一个日历月以及一个日期字段。我已经尝试了下面的一月示例,但是它变得越来越冗长,并且需要在所有月份中都这样做。可以将其缩短吗?

控制器:

var months = [{name: 'January', value: '01'},{name: 'February', value: '02'}]; 

    if (typeof filteredJan !== null && filteredJan.length > 0) {
      for(var i=0;i<filteredJan.length;i++){
        filteredJan[0].Month = 'JANUARY';
        filteredJan[i].StartDate = this.formatDate(filteredJan[i].StartDate);
        filteredJan[i].EndDate = this.formatDate(filteredJan[i].EndDate);

          if(filteredJan[i].StartDate[i].substr(0,2) === months[i].value){ 
              console.log(months[i].name);
              this.filteredDates(months)
          }
          debugger

        this.locationsFilteredJan(filteredJan);
      }
    }



    if (typeof filteredFeb !== null && filteredFeb.length > 0) {
      for(var i=0;i<filteredFeb.length;i++){
        //
        filteredFeb[i].StartDate = this.formatDate(filteredFeb[i].StartDate);
        filteredFeb[i].EndDate = this.formatDate(filteredFeb[i].EndDate);
        this.locationsFilteredFeb(filteredFeb);
      }
    }

客户:

<table >
   <thead>
      <tbody data-bind="foreach: locationsFilteredJan">
         <tr>  
             <td data-bind="text: Month"></td>
         </tr>    
      </tbody>
         <tr>
             <th>Event</th><th>Start Date</th><th>End Date</th> 
             <th>Location</th>
             <th>Book</th>
         </tr>
   </thead>
   <tbody data-bind="foreach: locationsFilteredJan">
      <tr>  
          <td data-bind="text: Title"></td>
          <td data-bind="text: $parent.formatDate(Start_x0020_Date)"></td>       
          <td data-bind="text: $parent.formatDate(End_x0020_Date)"></td>      
          <td data-bind="text: Location"></td>
          <td><a data-bind="text: Id, attr: { href: 
'https://web.powerapps.com/apps/?event_id='+ Id }">Book</a></td>
      </tr>    
   </tbody>
</table>
<table>
   <thead>
     <tr>  
         <td>FEBRUARY</td>
     </tr>
   </thead>
   <tbody data-bind="foreach: locationsFilteredFeb">
     <tr>  
         <td data-bind="text: Title"></td>
         <td data-bind="text: $parent.formatDate(Start_x0020_Date)"></td>       
         <td data-bind="text: $parent.formatDate(End_x0020_Date)"></td>      
         <td data-bind="text: Location"></td>
         <td><a data-bind="text: Id, attr: { href: 
   'https://web.powerapps.com/apps/?event_id='+ Id }">Book</a></td>
     </tr>    
   </tbody>
</table>`

我认为最好的方法是动态处理从新的Date读取的月份循环,然后根据当前数组位置的日期(filteredJan [i] .StartDate [i])将每个月(1月,2月等)推送到UI .substr(0,2))。当前Array位置包含每个事件都有一个日期的事件,并且拔出的日历月份需要与Array中的该日期匹配,并在UI中按正确的月份对每个事件进行排序。目前,它的功能如上所述,但是太冗长,需要更简单,更快速的性能。

注意更新: 可以使它与像这样的简单对象一起工作:

var events =  [
    {name: 'Skiing',          value: '02/01/2018'},
    {name: 'Skydiving',       value: '28/02/2018'},
    {name: 'Sledging',        value: '15/01/2018'}]; 
var months = [
    {name: 'JANUARY',        value: '09/01/2018'},
    {name: 'FEBRUARY',       value: '19/02/2018'}]; 

var companyUsers = {}// hashmap of users using companyId as keys

events.forEach(function(user){
  var id= user.value.substring(3, 5);
  //console.log(id);
  companyUsers[id] = companyUsers[id]||[]; 
  companyUsers[id].push(user)
});
var text = "";
// map new array based on each subscription
var res = months.map(function(sub){
  sub.events = companyUsers[sub.value.substring(3, 5)] || [];      
  text += sub.events[sub] + "<br>"; 
  return sub;

});

//push to view
console.log(res)

但不是这样:

<table class="table">
    <thead>
      <tr>
        <th scope="col">Title</th>
        <th scope="col">Start Date</th>
        <th scope="col">End Date</th>
        <th scope="col">Booking</th>
      </tr>
    </thead>
    <tr><td><h4>JANUARY</h4> </td></tr>  
    <tbody data-bind="foreach: locationsFilteredMonths">
        <tr>  
          <td data-bind="text: name"></td>
         </tr>    
    </tbody>   
          <tbody data-bind="foreach: $parent.data[locationsFilteredMonths]">
              <tr>  
                <td data-bind="text: Title"></td>
                <td data-bind="text: $parent.formatDate(Start_x0020_Date)"></td>       
                <td data-bind="text: $parent.formatDate(End_x0020_Date)"></td>      
                <td data-bind="text: Location"></td>
                <td><a data-bind="text: Id, attr: { href: 'https://web.powerapps.com/apps/?event_id='+ Id }">Book</a></td>
              </tr>    
          </tbody>    
  </table>

控制器:

 var months = [
    {name: 'JANUARY',        value: '01'},
    {name: 'FEBRUARY',       value: '02'},
    {name: 'MARCH',           value: '03'},
    {name: 'APRIL',           value: '04'},
    {name: 'MAY',             value: '05'},
    {name: 'JUNE',            value: '06'},
    {name: 'JULYS',           value: '07'},
    {name: 'AUGUST',          value: '08'},
    {name: 'SEPTEMBER',       value: '09'},
    {name: 'OCTOBER',         value: '10'},
    {name: 'NOVEMBER',        value: '11'},
    {name: 'DECEMBER',        value: '12'}]; 

var eventsHash = {};
    //format API dates
     if (typeof filteredEvents !== null && filteredEvents.length > 0) {
        var i:any;
        for(i=0;i<filteredEvents.length;i++){
          filteredEvents[i].StartDate = this.formatDate(filteredEvents[i].StartDate);
          filteredEvents[i].EndDate = this.formatDate(filteredEvents[i].EndDate);
        }
      }

     filteredEvents.forEach(function(event){
        //get position of month and use as id
        var monthStr = event.StartDate.substring(3, 5);
        console.log(monthStr);
        eventsHash[monthStr] = eventsHash[monthStr]||[]; 
        eventsHash[monthStr].push(event);
    });

    var filteredMonths = months.map(function(sub){
      sub.value = eventsHash[sub.name];      
      //text += sub.events[sub] + "<br>"; 
      return sub;
    });

    //for each month show events
    this.locationsFilteredMonths(filteredMonths);
    this.locationsFilteredYears(filteredEvents);

1 个答案:

答案 0 :(得分:0)

一种方法是将数据转换为以月份名称作为键的对象,如下所示:

{
    'January': [
        {
            Id: '',
            Title: 'Foo',
            Start_x0020_Date: '',
            End_x0020_Date: '',
            Location: ''
        },
        {
            Id: '',
            Title: 'Foo',
            Start_x0020_Date: '',
            End_x0020_Date: '',
            Location: ''
        }
    ],
    'February': [
        {
            Id: '',
            Title: 'Foo',
            Start_x0020_Date: '',
            End_x0020_Date: '',
            Location: ''
        },
        {
            Id: '',
            Title: 'Foo',
            Start_x0020_Date: '',
            End_x0020_Date: '',
            Location: ''
        }
    ]
}

如何执行此操作完全取决于您的源数据,但是我假设您是从某个API获取的,这只是事件的一大集合。只需一个循环。

然后您的模板将如下所示:

<!-- ko foreach: { data: Object.keys(data), as: 'month' } -->
<table>
   <thead>
     <tr>  
         <td data-bind="text: month"></td>
     </tr>
   </thead>
   <tbody data-bind="foreach: $parent.data[month]">
     <tr>  
         <td data-bind="text: Title"></td>
         <td data-bind="text: $parents[1].formatDate(Start_x0020_Date)"></td>       
         <td data-bind="text: $parents[1].formatDate(End_x0020_Date)"></td>      
         <td data-bind="text: Location"></td>
         <td><a data-bind="text: Id, attr: { href: 'https://web.powerapps.com/apps/?event_id='+ Id }">Book</a></td>
     </tr>    
   </tbody>
</table>
<!-- /ko -->

编辑:

这是一个工作的小提琴:https://jsfiddle.net/thebluenile/5yL0knm9/