2013-08-13 29 views
25

Tôi đang tạo bảng có d3 để sử dụng bởi FooTable jquery plugin và điều này yêu cầu phải có một số thuộc tính dữ liệu trong hàng tiêu đề. Nhưng không phải tất cả các cột đều có thuộc tính dữ liệu và tự hỏi liệu có cách nào để thực hiện điều này hay không.d3 thêm thuộc tính dữ liệu có điều kiện

Cách tiếp cận này sắp xếp các công trình, bằng cách thêm tất cả các thuộc tính dữ liệu có thể và để trống một số, nhưng tôi chắc chắn đó là cách thực hành không tốt.

var th = d3.select(selection).select("thead").selectAll("th") 
      .data(colspec) 
      .enter().append("th") 
      .text(function(d) { return d["data-name"]; }) 
      .attr("data-class", function(d) { 
       if ("data-class" in d) { 
        return d["data-class"]; 
       } else { 
        return ""; 
       } 
      }) 
      .attr("data-hide", function(d) { 
       if ("data-hide" in d) { 
        return d["data-hide"]; 
       } else { 
        return ""; 
       } 
      }) 
      .attr("data-ignore", function(d) { 
       if ("data-ignore" in d) { 
        return d["data-ignore"]; 
       } else { 
        return ""; 
       } 
      }) 

     etc. 

colspec dụ:

[{"data-name": "username"}, {"data-name": "Date Joined", "data-hide": "true"}] 

Hiện nay nhận:

<th data-class="" data-hide="true" data-ignore="" data-type="">Joined</th> 

Muốn

<th data-hide="true" >Joined</th> 

Bất kỳ lời đề nghị?

+0

+ 1'd kết quả chỉ dành riêng cho giới thiệu tôi đến FooTable – Joum

+0

vì vậy, nếu tôi nhận được câu hỏi thẳng, khi một tế bào nào đó không có dữ liệu, bạn muốn phiên bản _minified_ của bảng để * * không ** hiển thị trường, phải không? – Joum

+0

Không cố gắng để được thông minh (chưa!) Thêm bình luận ở trên. – PhoebeB

Trả lời

26

Có vẻ như một ứng cử viên tốt cho .each():

var th = d3.select(selection).select("thead").selectAll("th") 
     .data(colspec) 
    .enter().append("th") 
     .text(function(d) { return d["data-name"]; }) 
     // now address each item individually 
     .each(function(d) { 
      var header = d3.select(this); 
      // loop through the keys - this assumes no extra data 
      d3.keys(d).forEach(function(key) { 
       if (key != "data-name") 
        header.attr(key, d[key]); 
      }); 
     }); 

Tôi thường sử dụng .each khi có mỗi mục phạm vi có ý nghĩa hơn cố gắng tìm ra một loạt các thuộc tính cho từng hạng mục.

Đối với một danh sách ngắn các thuộc tính, đặc biệt là nếu bạn đang lo lắng về dữ liệu bổ sung trong các đối tượng, nó có thể dễ dàng hơn để lặp qua các phím mong muốn thay vì tất cả mọi thứ:

 .each(function(d) { 
      var header = d3.select(this); 
      ['data-class', 'data-hide', 'data-ignore'].forEach(function(key) { 
       if (key in d) 
        header.attr(key, d[key]); 
      }); 
     }); 
+1

Ồ thật thông minh! Cảm ơn. – PhoebeB

+0

tại sao bạn cần một forEach bên trong một .each? – Kraken

+0

.each vòng qua các đối tượng dữ liệu (hàng), trong khi trong ví dụ này, forEach đang lặp qua các thuộc tính được áp dụng cho từng mục (cols). – nrabinowitz

6

Bạn có thể sử dụng chức năng .filter() để chỉ hoạt động trên tập hợp con của lựa chọn mà bạn cần đặt thuộc tính cho, ví dụ:

var th = d3.select(selection).select("thead").selectAll("th") 
     .data(colspec) 
     .enter().append("th") 
     .text(function(d) { return d["data-name"]; }); 
th.filter(function(d) { return ("data-class" in d); }) 
     .attr("data-class", function(d) { 
      return d["data-class"]; 
     }); 
+0

Tôi đã hy vọng tránh phải vượt qua các yếu tố sáu lần (số thuộc tính dữ liệu), mặc dù ý tưởng bộ lọc sẽ làm cho nó ít nguy hiểm. Không có cách nào để làm điều đó nội tuyến trong một vượt qua? – PhoebeB

+0

Một cách tiếp cận khác là chỉ cần gọi một hàm trên mỗi phần tử thực hiện cài đặt chuyển đổi và thuộc tính. Bằng cách này, bạn sẽ chỉ chạm vào từng phần tử một lần. –

44

Bạn không cần phải gọi each() hoặc filter() ... Hàm attr() sẽ làm điều này cho bạn nội bộ. Chỉ cần gọi nó với một hàm thay vì một giá trị, và có hàm trả về giá trị mong muốn cho mỗi dữ kiện, hoặc null nếu thuộc tính không mong muốn cho một cột mốc đặc biệt, như vậy:

... 
.attr('data-class', function(d) { 
    return 'data-class' in d ? d['data-class'] : null; 
}); 

Nếu trở về chức năng của bạn null, thuộc tính không được thêm vào. Bạn thậm chí có thể kết hợp nhiều thuộc tính vào một cuộc gọi bằng cách cung cấp bản đồ tên attr cho các chức năng như vậy:

... 
.attr({ 
    'data-class': function(d) { 
     return 'data-class' in d ? d['data-class'] : null; 
    }, 
    'data-hide': function(d) { 
     return 'data-hide' in d ? d['data-hide'] : null; 
    }, 
    'data-ignore': function(d) { 
     return 'data-ignore' in d ? d['data-ignore'] : null; 
    } 
}); 

hoặc nếu bạn thích tôi và không muốn nhập quá nhiều, bạn có thể giảm danh sách thuộc tính tên vào bản đồ thích hợp:

... 
.attr(['data-class', 'data-hide', 'data-ignore'].reduce(function(result, attr) { 
    result[attr] = function(d) { 
     return attr in d ? d[attr] : null; 
    } 
    return result; 
}, {})); 
+8

+1 để chỉ định rằng thuộc tính null không được thêm – Breiz

+0

hoạt động tốt nếu có các biến thể nhỏ để hiển thị dựa trên dữ liệu. Nếu bạn muốn hiển thị một đối tượng hoàn toàn khác dựa trên một số khóa dữ liệu, tôi nghĩ .each() gọn gàng hơn. – bryanph

Các vấn đề liên quan