在没有 InfoPath 的情况下向 SharePoint 表单添加重复控件的解决方法

Workaround to add repetitive controls to a SharePoint form without InfoPath

我正在尝试创建一个重复的 SharePoint 表单controls.I我是 SharePoint Online 用户 (Office 365)。

我正在寻找一种解决方法来执行此操作,而无需使用 InfoPath 或任何第三方软件(如 Nintex)。 JavaScript 解决方案是理想的。

非常感谢任何建议。

既然您知道如何将 JavaScript 插入表单,您就可以将重复数据存储在多行文本字段中。

在多行文本字段中以结构化格式存储数据,例如 JSON,然后使用 JavaScript 读取该字段的值并呈现适当的重复控件(标签、文本输入,下拉菜单)在屏幕上。

查看下面我丑陋但实用的示例(用您要在其中存储重复数据的多行文本字段的显示名称替换单词 "Multiline Text Column"):

(function(){
  // define the data you want captured in the repeating field
  var fields = [{type:"text",label:"Employee Name"},
              {type:"text",label:"ID Number"},
              {type:"choice",label:"Status",choices:["Full Time","Part Time","Intern","Consultant"]}
             ];
  // find and hide the text area
  var textarea = document.querySelector("[title=\"Multiline Text Column\"]");
  // textarea.style.display = "none"; // uncomment this line to hide the text area
  // create a new container for your repeating field
  var repeatingData = [];
  var container = document.createElement("div");
  textarea.parentNode.appendChild(container);
  // add a button for adding new rows
  var addButton = document.createElement("input"); 
  addButton.setAttribute("type","button");
  addButton.value = "Add row";
  addButton.addEventListener("click",function(){addRow();});
  textarea.parentNode.appendChild(addButton);
  // get the existing data, if any
  var existing = JSON.parse(textarea.value);
  for(var i = 0; i < existing.length; i++){
    addRow(existing[i]);
  }
  function addRow(data){
    if(typeof data === "undefined"){
      data = {};
    }
    repeatingData.push(data);
    var last = repeatingData.length-1;
    var index = last;
    if(last > 0){index = repeatingData[index-1]["data-id"] + 1;}
    repeatingData[last]["data-id"] = index;
    var row = document.createElement("div");   
    row.setAttribute("data-id",index);
    row.style.border = "1px solid black";
    row.style.margin = "2px"; row.style.padding = "2px";
    for(var i = 0; i < fields.length; i++){
      var field = fields[i];
      var lbl = document.createElement("span");
      lbl.insertAdjacentHTML("beforeend",field.label+": ");
      row.appendChild(lbl);
      switch(field.type){
          case "text":      
            var txt = document.createElement("input");
            txt.setAttribute("type","text");
            if(data[field.label]){
               txt.value = data[field.label];
            }
            (function(label){
              txt.addEventListener("keyup",function(){
                getRecord(index)[label]=this.value;
                updateTextArea();});
            })(field.label);
            row.appendChild(txt);
            break;
          case "choice":
            var sel = document.createElement("select");
            var option = sel.appendChild(document.createElement("option"));
            option.value = "";
            option.innerHTML = "";
            for(var j = 0; j < field.choices.length; j++){
              option = document.createElement("option");
              option.value = field.choices[j];
              option.appendChild(document.createTextNode(field.choices[j]));
              sel.appendChild(option);
            }
            if(data[field.label]){
               sel.value = data[field.label];
            }
            (function(label){
              sel.addEventListener("change",function(){
                getRecord(index)[label]=this.value;
                updateTextArea();});
            })(field.label);
            row.appendChild(sel);
            break;
      }
      row.appendChild(document.createElement("br"));
    }
    var remove = document.createElement("a");
    remove.href = "return false;";
    row.appendChild(remove);
    remove.innerHTML = "remove";    
    remove.addEventListener("click",function(event){
      event.preventDefault(); 
      repeatingData.splice(getRecordIndex(index),1); 
      container.removeChild(row); 
      updateTextArea();
      return false;});
    container.appendChild(row);
    updateTextArea();
  }
  function getRecord(i){
    return repeatingData[getRecordIndex(i)];
  }
  function getRecordIndex(i){
    for(var j = 0; j < repeatingData.length; j++){
      if(repeatingData[j]["data-id"] == i){
        return j;
      }
    }
    return -1;
  }
  function updateTextArea(){
    textarea.value = JSON.stringify(repeatingData);
  }
})();
.ms-formtable{
  font-family:"Segoe UI","Segoe",Tahoma,Helvetica,Arial,sans-serif;
  font-size:13px;
  font-weight:400;
}
.ms-formlabel{  
  padding-right:5px;
}
.ms-long{ border:1px solid rgb(186,186,186); padding-left:5px; padding-right:5px; padding-bottom:2px; padding-top:2px;
<table class="ms-formtable">
<tr>
  <td width="113" class="ms-formlabel" valign="top">
    <span class="ms-h3 ms-standardheader"><nobr>Multiline Text Column</nobr></span>
  </td>
  <td width="350" class="ms-formbody" valign="top">
     <span dir="none"><textarea class="ms-long" title="Multiline Text Column" cols="20">[{"Employee Name":"Joe Blow","ID Number":"123","Status":"Full Time"},{"Employee Name":"Jane Doe","ID Number":"321","Status":"Consultant"}]</textarea></span>
  </td>
</tr>
</table>

请注意,只要行控件中的值发生变化,textarea 中的基础值就会发生变化。保存表单时,textarea 中的值将保存到 SharePoint。

请注意,您需要稍微不同(更简单)的代码才能使其适用于显示表单和编辑表单。