使用JSON数据和变量列

时间:2018-01-20 17:20:04

标签: reactjs typescript

我有以下JSON数据:

{
    "languageKeys": [{
        "id": 1,
        "project": null,
        "key": "GENERIC.WELCOME",
        "languageStrings": [{
            "id": 1,
            "content": "Welcome",
            "language": {
                "id": 1,
                "key": "EN"
            }
        }]
    }, {
        "id": 2,
        "project": null,
        "key": "GENERIC.HELLO",
        "languageStrings": [{
            "id": 2,
            "content": "Hej",
            "language": {
                "id": 2,
                "key": "DK"
            }
        }, {
            "id": 5,
            "content": "Hello",
            "language": {
                "id": 1,
                "key": "EN"
            }
        }]
    }, {
        "id": 3,
        "project": null,
        "key": "GENERIC.GOODBYE",
        "languageStrings": []
    }]
}

我希望将其转换为列可变的表。

表格输出应如下所示:

------------------------------------------------
| Key             | EN      | DK  | SE | [...] |
| GENERIC.WELCOME | Welcome |     |    |       |
| GENERIC.HELLO   | Hello   | Hej |    |       |
| GENERIC.GOODBYE |         |     |    |       |
------------------------------------------------

正如您所看到的,该表在行和列中都是动态的,我正在努力弄清楚如何在每个" EN"," DK&#中映射正确的数据34;," SE" [...]字段到正确的列,因为当我从API获取JSON响应时它们不是必需的。

到目前为止,我得到了以下渲染功能:

private static renderLanguageKeysTable(languageKeys: ILanguageKey[], languages: ILanguage[]) {
    return <table>
               <thead>
               <tr>
                   <td>Key</td>
                   {languages.map(language =>
                    <td key={language.id}>{language.key}</td>
                )}
               </tr>
               </thead>
               <tbody>
               {languageKeys.map(languageKey =>
                <tr key={languageKey.id}>
                    <td>{languageKey.key}</td>
                    {languages.map(language =>
                        <td key={language.id}>

                        </td>
                    )}
                </tr>
            )}
               </tbody>
           </table>
        ;
}

这样可以正常工作,唯一缺少的部分是列中的数据。

我尝试了filtermap的各种变体,但是没有按照我希望的方式制作出来。

我正在使用ReactJS并使用打字稿(es2015)

进行编写

澄清一下: 列始终由API定义,并且行不能具有指向不存在的列的ID,因为它们在后端中是相关的。 然而,有些行可能没有所有列,在这种情况下它们应该只是空白

3 个答案:

答案 0 :(得分:0)

&#13;
&#13;
const findDistinctLang = (langKeys) => {
  let langString = []
  langKeys.forEach((element) => {
    if(element.languageStrings.length !== 0) {
      langString = [...langString, ...element.languageStrings]
    }
    
  })
 
  const langArr = []

  langString.forEach((element) => {
    if (langArr.indexOf(element.language.key) === -1) {
      langArr.push(element.language.key)
    }
  })
  return langArr
}

class Table extends React.Component {
    state = {
      "languageKeys": [{
        "id": 1,
        "project": null,
        "key": "GENERIC.WELCOME",
        "languageStrings": [{
          "id": 1,
          "content": "Welcome",
          "language": {
            "id": 1,
            "key": "EN"
          }
        }]
      }, {
        "id": 2,
        "project": null,
        "key": "GENERIC.HELLO",
        "languageStrings": [{
          "id": 2,
          "content": "Hej",
          "language": {
            "id": 2,
            "key": "DK"
          }
        }, {
          "id": 5,
          "content": "Hello",
          "language": {
            "id": 1,
            "key": "EN"
          }
        }]
      }, {
        "id": 3,
        "project": null,
        "key": "GENERIC.GOODBYE",
        "languageStrings": [{
          "id": 2,
          "content": "Hej",
          "language": {
            "id": 2,
            "key": "DK"
          }
        },{
          "id": 5,
          "content": "XYZ",
          "language": {
            "id": 7,
            "key": "XYZ"
          }
        }]
      }]
    }
    getContentName = (languageSet, langName) => {
     return _.find(languageSet.languageStrings, function(o) { return o.language.key === langName })
    }
    render() {
      const lanKeyArr = findDistinctLang(this.state.languageKeys)
      return ( <
        table >
        <
        thead >
        <
        tr >
        <
        td > Key < /td> {
          lanKeyArr.map((lang) => {
                return ( < td > {
                    lang
                  } < /td>)
                })
            } <
            /tr> <
            /thead> <
          tbody >
          {
          this.state.languageKeys.map((languageSet) => {
          
          return(
           <tr>
           <td>{languageSet.key}</td>
           {[...lanKeyArr].map((element, index) => {
             const contentObj = this.getContentName(languageSet, element)
             return (
             <td>{contentObj && contentObj.content || ""}</td>
             )
           })
           }
           </tr>
          )
           
          })
          }
            <
            /tbody> < /
            table >

        )
      }
    }
    
    ReactDOM.render(<Table />,document.getElementById("root"))
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
&#13;
&#13;
&#13;

我已根据您提供的测试数据实施, 注意:你可以使它更干净,只是通过这个例子给你一个想法

答案 1 :(得分:0)

您可以根据预期的渲染来解析对象并渲染表。

注意,使用ReactJS的经验很少,并且没有尝试过TypeScript

let languages = {"languageKeys":[{"id":1,"project":null,"key":"GENERIC.WELCOME","languageStrings":[{"id":1,"content":"Welcome","language":{"id":1,"key":"EN"}}]},{"id":2,"project":null,"key":"GENERIC.HELLO","languageStrings":[{"id":2,"content":"Hej","language":{"id":2,"key":"DK"}},{"id":5,"content":"Hello","language":{"id":1,"key":"EN"}}]},{"id":3,"project":null,"key":"GENERIC.GOODBYE","languageStrings":[]}]};

const table = document.querySelector("table");
const thead = table.querySelector("thead").querySelector("tr");
const tbody = table.querySelector("tbody");

Object.values(languages.languageKeys).forEach(({key, languageStrings}) => {
  // check if `languageStrings` array has `.length` greater than `0`
  if (languageStrings.length) {
    languageStrings.forEach(({content, language:{key:lang}}) => {
    console.log(key, content, lang);
    // use block scopes
    { 
      // check if the `lang` is already appended to `<thead>`
      if (![...thead.querySelectorAll("td")].find(({textContent}) => textContent === lang)) {
      let td = document.createElement("td");
      td.textContent = lang;
      thead.appendChild(td);
      }
    }
    {
      // append `key`
      let tr = document.createElement("tr");
      let tdKey = document.createElement("td");
      tdKey.textContent = key;
      tr.appendChild(tdKey);
      // append `content`
      let tdContent = document.createElement("td");
      tdContent.textContent = content;
      tr.appendChild(tdKey);
      tr.appendChild(tdContent);
      tbody.appendChild(tr);      
      // append a `<td>` for placing `<td>` in correct column
      // not an optimal approach, adjust if necessary
      if ([...thead.querySelectorAll("td")].findIndex(el => el.textContent === lang) === tr.children.length) {
        tr.insertBefore(document.createElement("td"), tr.lastElementChild);
      };
    }
   })
  } else { 
      // handle empty `languageStrings` array
      let tr = document.createElement("tr");
      let tdKey = document.createElement("td");
      tdKey.textContent = key;
      tr.appendChild(tdKey);
      tbody.appendChild(tr);
  }
})
<table>
  <thead>
    <tr>
      <td>Key</td>
    </tr>
  </thead>
  <tbody>  
  </tbody>
</table>

答案 2 :(得分:0)

我最终采用了与建议不同的方法(经过良好的睡眠和一些思考后)

基本上,我为每个单独的单元格创建了一个新组件,导致代码表格侧面的以下渲染:

private static renderLanguageKeysTable(languageKeys: ILanguageKey[], languages: ILanguage[]) {
    return <table>
               <thead>
               <tr>
                   <th>Key</th>
                   {languages.map(language =>
                    <th key={language.id}>{language.key}</th>
                )}
               </tr>
               </thead>
               <tbody>
               {languageKeys.map(languageKey =>
                <tr key={languageKey.id}>
                    <td>{languageKey.key}</td>
                    {languages.map(language =>
                        <Cell language={language} languageKey={languageKey} key={language.id} />
                    )}
                </tr>
            )}
               </tbody>
           </table>
        ;
}

以下代码用于渲染每个单元格:

import * as React from "react";

export class Cell extends React.Component {
    render() {
        let string: any;
        if (this.props.languageKey && this.props.languageKey.languageStrings) {
            let languageString =
                this.props.languageKey.languageStrings.find((i: any) => i.language.id === this.props.language.id);
            if (languageString === null || languageString === undefined) {
                string = "";
            } else {
                string = languageString.content;
            }
        } else {
            string = "";
        }
        return <td>
            {string}
        </td>;
    }

    props: any;
}