结构化和绑定(ajax响应)

时间:2016-04-12 18:23:16

标签: javascript json data-binding binding traversal

我在多年编码中遇到的一个常见模式是来自服务器响应(XMLHttpRequest)的数据的结构化/绑定。这个创建元素并以特定顺序附加它们以及绑定(属性,事件,内容)的问题是我在这里想要实现的。

出于示例目的和简单性,我试图创建一个tr --- td嵌套结构,并绑定var instructs对象的属性(table-row,table-data)。

JSON响应(虚拟数据)

var response =[{"employeeNumber":"1002","lastName":"Murphy","firstName":"Diane","extension":"x5800","email":"dmurphy@classicmodelcars.com","officeCode":"1","reportsTo":null,"jobTitle":"President"},{"employeeNumber":"1056","lastName":"Patterson","firstName":"Mary","extension":"x4611","email":"mpatterso@classicmodelcars.com","officeCode":"1","reportsTo":"1002","jobTitle":"VP Sales"},{"employeeNumber":"1076","lastName":"Firrelli","firstName":"Jeff","extension":"x9273","email":"jfirrelli@classicmodelcars.com","officeCode":"1","reportsTo":"1002","jobTitle":"VP Marketing"},{"employeeNumber":"1088","lastName":"Patterson","firstName":"William","extension":"x4871","email":"wpatterson@classicmodelcars.com","officeCode":"6","reportsTo":"1056","jobTitle":"Sales Manager (APAC)"},{"employeeNumber":"1102","lastName":"Bondur","firstName":"Gerard","extension":"x5408","email":"gbondur@classicmodelcars.com","officeCode":"4","reportsTo":"1056","jobTitle":"Sale Manager (EMEA)"},{"employeeNumber":"1143","lastName":"Bow","firstName":"Anthony","extension":"x5428","email":"abow@classicmodelcars.com","officeCode":"1","reportsTo":"1056","jobTitle":"Sales Manager (NA)"},{"employeeNumber":"1165","lastName":"Jennings","firstName":"Leslie","extension":"x3291","email":"ljennings@classicmodelcars.com","officeCode":"1","reportsTo":"1143","jobTitle":"Sales Rep"},{"employeeNumber":"1166","lastName":"Thompson","firstName":"Leslie","extension":"x4065","email":"lthompson@classicmodelcars.com","officeCode":"1","reportsTo":"1143","jobTitle":"Sales Rep"},{"employeeNumber":"1188","lastName":"Firrelli","firstName":"Julie","extension":"x2173","email":"jfirrelli@classicmodelcars.com","officeCode":"2","reportsTo":"1143","jobTitle":"Sales Rep"},{"employeeNumber":"1216","lastName":"Patterson","firstName":"Steve","extension":"x4334","email":"spatterson@classicmodelcars.com","officeCode":"2","reportsTo":"1143","jobTitle":"Sales Rep"},{"employeeNumber":"1286","lastName":"Tseng","firstName":"Foon Yue","extension":"x2248","email":"ftseng@classicmodelcars.com","officeCode":"3","reportsTo":"1143","jobTitle":"Sales Rep"},{"employeeNumber":"1323","lastName":"Vanauf","firstName":"George","extension":"x4102","email":"gvanauf@classicmodelcars.com","officeCode":"3","reportsTo":"1143","jobTitle":"Sales Rep"},{"employeeNumber":"1337","lastName":"Bondur","firstName":"Loui","extension":"x6493","email":"lbondur@classicmodelcars.com","officeCode":"4","reportsTo":"1102","jobTitle":"Sales Rep"},{"employeeNumber":"1370","lastName":"Hernandez","firstName":"Gerard","extension":"x2028","email":"ghernande@classicmodelcars.com","officeCode":"4","reportsTo":"1102","jobTitle":"Sales Rep"},{"employeeNumber":"1401","lastName":"Castillo","firstName":"Pamela","extension":"x2759","email":"pcastillo@classicmodelcars.com","officeCode":"4","reportsTo":"1102","jobTitle":"Sales Rep"},{"employeeNumber":"1501","lastName":"Bott","firstName":"Larry","extension":"x2311","email":"lbott@classicmodelcars.com","officeCode":"7","reportsTo":"1102","jobTitle":"Sales Rep"},{"employeeNumber":"1504","lastName":"Jones","firstName":"Barry","extension":"x102","email":"bjones@classicmodelcars.com","officeCode":"7","reportsTo":"1102","jobTitle":"Sales Rep"},{"employeeNumber":"1611","lastName":"Fixter","firstName":"Andy","extension":"x101","email":"afixter@classicmodelcars.com","officeCode":"6","reportsTo":"1088","jobTitle":"Sales Rep"},{"employeeNumber":"1612","lastName":"Marsh","firstName":"Peter","extension":"x102","email":"pmarsh@classicmodelcars.com","officeCode":"6","reportsTo":"1088","jobTitle":"Sales Rep"},{"employeeNumber":"1619","lastName":"King","firstName":"Tom","extension":"x103","email":"tking@classicmodelcars.com","officeCode":"6","reportsTo":"1088","jobTitle":"Sales Rep"},{"employeeNumber":"1621","lastName":"Nishi","firstName":"Mami","extension":"x101","email":"mnishi@classicmodelcars.com","officeCode":"5","reportsTo":"1056","jobTitle":"Sales Rep"},{"employeeNumber":"1625","lastName":"Kato","firstName":"Yoshimi","extension":"x102","email":"ykato@classicmodelcars.com","officeCode":"5","reportsTo":"1621","jobTitle":"Sales Rep"},{"employeeNumber":"1702","lastName":"Gerard","firstName":"Martin","extension":"x2312","email":"mgerard@classicmodelcars.com","officeCode":"4","reportsTo":"1102","jobTitle":"Sales Rep"}];

绑定(说明)

var instructs={
    tag:"tr",
    attributes:{class:"table-row"},
    props:{
        email:{
            tag:"td",
            content: null,
            attributes:{class:"table-data",id:"table-data-id"}
        },
        employeeNumber:{
            tag:"td",
            attributes:{class:"table-data"},
            content: null,
            props:{
                x:{
                    tag: "input",
                    attributes:{class:"table-input"},
                    content: "test"
                }
            }
        },
        extension:{
            tag:"td",
            content: null,
            attributes:{class:"table-data"}
        },
        firstName:{
            tag:"td",
            content: null,
            attributes:{class:"table-data"}
        },
        jobTitle:{
            tag:"td",
            content: null,
            attributes:{class:"table-data"}
        },
        lastName:{
            tag:"td",
            content: null,
            attributes:{class:"table-data"}
        },
        officeCode:{
            tag:"td",
            content: null,
            attributes:{class:"table-data"}
        },
        reportsTo:{
            tag:"td",
            content: null,
            attributes:{class:"table-data"}
        }
    }
};

我的功能(组装)

function assemble(r,s,n){
    var n = n || new DocumentFragment();    
    if(typeof r !== 'string'){ //HAS CHILDREN
        r.forEach((o)=>{ 
            for(y in s){
                switch(y){
                    case "tag":
                        var tag = document.createElement(s[y]);
                        n.appendChild(tag);
                        break;
                    case "attributes":
                        for(a in s[y]) tag.setAttribute(a,s[y][a]);
                        break;
                    case "content":
                        if(s.content === null){
                            //append current property value
                        }
                        else{
                            tag.innerHTML = s.content;
                        }
                        break;
                    case "props":
                        for(k in o) assemble(k,s[y][k],tag); //EXECUTE PER CHILDREN
                        break;
                }
            }
        });
    }
    else{
        for(x in s){
            switch(x){
                case "tag":
                    var tag = document.createElement(s[x]);
                    n.appendChild(tag);
                    break;
                case "content":
                    if(s.content === null){
                        //append current property value
                    }
                    else{
                        tag.innerHTML = s.content;
                    }
                    break;
                case "attributes":
                    for(a in s[x]) tag.setAttribute(a,s[x][a]);
                    break;
                case "props":
                    for(c in s[x]) assemble(r,s[x][c],tag);
                    break;
            }
        }   
        return n;
    }
    return n;
}               

document.addEventListener('DOMContentLoaded',()=>{
     var data = assemble(response,instructs);           
     console.log(data);
});

我正在寻找的最终结果是嵌套tr> td的数组/片段,它们都具有class属性,并且值附加到innerHTML

<tr class ="table-row">
    <td class="table-data">how do I bind the response values?</td>
    <td class="table-data">how do I bind the response values?</td>
    <td class="table-data">how do I bind the response values?</td>
    <td class="table-data">how do I bind the response values?</td>
    <td class="table-data">how do I bind the response values?</td>
    <td class="table-data">how do I bind the response values?</td>
    <td class="table-data">how do I bind the response values?</td>
</tr>

问题:

如何将响应中的属性值绑定到innerHTML的{​​{1}}?

2 个答案:

答案 0 :(得分:1)

尝试以下方法。对不起,我开始重构你的,最后我重写了它。注意file总是被视为innerHTML,区分文本(追加createTextNode func结果)和html(innerHTML prop)根本不是一个坏主意。在您的数据中content应该移到instructs.props.employeeNumber.props.x.content,看看输入[text]标记的工作原理。顺便说一下,我看到有很多东西可以在这里讨论。希望它有所帮助!

instructs.props.employeeNumber.props.x.attributes.value

答案 1 :(得分:1)

虽然我的答案没有解决问题中的代码上下文,但是对于结构化和绑定json响应,我通常使用正则表达式模板。我觉得简单,简洁。前,

HTML:

<table>
  <tbody id="employee">
  </tbody>
</table>

JS:

var template = function(tpl, data) {
  return tpl.replace(/\$\{([^\}]+)?\}/g, function($1, $2) {
    return data[$2];
  });
};

var rowTemplate = '<tr class ="table-row">\
                     <td class="table-data">${email}</td>\
                     <td class="table-data"><input type="text" value=' ${employeeNumber}' /></td>\
                     <td class="table-data">${firstName}</td>\
                     <td class="table-data">${lastName}</td>\
                     <td class="table-data">${email}</td>\
                     <td class="table-data">${jobTitle}</td>\
                     <td class="table-data">${extension}</td>\
                   </tr>';

var response = [{"employeeNumber":"1002","lastName":"Murphy","firstName":"Diane","extension":"x5800","email":"dmurphy@classicmodelcars.com","officeCode":"1","reportsTo":null,"jobTitle":"President"}, ....]

var b = document.getElementById('employee');

for (var i = 0; i < response.length; i++) {
  var tr = document.createElement('x');
  b.appendChild(tr);
  tr.outerHTML = template(rowTemplate, response[i]);
}

fiddle

希望这会有所帮助。