Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3js accept/revert input values

Tags:

d3.js

I fill a set of text input fields displaying values of an associative array using d3js. The user changes some input values.

var obj = {a: 'Hello', b: 'World'}
var kk = function(d){return d.key}
var kv = function(d){return d.value}
var upd = function(c){
    c.select('div.label').text(kk)
    c.select('div.input input').attr("value", kv)
}
var data = d3.entries(obj)
var prop = d3.select("div.container").selectAll("div.prop").data(data, kk)
upd(prop)
var eprop = prop.enter().append("div").attr("class", "prop")
eprop.append("div").attr("class", "label")
eprop.append("div").attr("class", "input").append("input").attr("name", kk)
upd(eprop)
prop.exit().remove()

What are the best practices to
a) update the original associative array from DOM (opposite direction)
b) revert the DOM values to the original ones

My current solutions are
a) iterating over the input fields d3.select("div.container").selectAll("div.prop").select('div.input input').each(function(){obj[this.name]=this.value})
b) assigning [] as selection data and then back the original data (I have not found anything like force update or refresh)

Edit (generalized)
Input fields displaying values of an associative array is only a special case, you can imagine any d3js layout applied on a model with user interaction.
But generally:
a) accept the values from the DOM back to the source data
b) revert the DOM to the actual source data
Is there any d3js built-in support or a d3js plugin for this?

like image 754
Pavel Gatnar Avatar asked Aug 01 '15 14:08

Pavel Gatnar


2 Answers

You really need to provide some code because from your question it's tough to tell how you are using d3 to manage your inputs. I'm assuming you are data-binding in some fashion so I just coded this up for fun. It's shows some of the cools ways to use enter/append, data() and datum() to manage groups of input and their values:

<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected]" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>

<body>
  <button id="report">Report</button>
  <button id="reset">Reset</button>
  <script>
    var data = [{
      v: Math.random()
    }, {
      v: Math.random()
    }, {
      v: Math.random()
    }, {
      v: Math.random()
    }, {
      v: Math.random()
    }, {
      v: Math.random()
    }];

    var inputs = d3.select('body')
      .append('div')
      .selectAll('input')
      .data(data)
      .enter()
      .append('input')
      .attr('type','text')
      .attr('value', function(d) {
        return d.v;
      })
      .on('blur', function(d) {
        d._v = d.v;
        d.v = this.value;
      });
      
    d3.select('#report')
      .on('click',function(){
        alert(inputs.data().map(function(d){
          return d.v;
        }).join("\n"));
      });
      
    d3.select('#reset')
      .on('click',function(){
        inputs.each(function(d){
          if (d._v){
            this.value = d._v;
            d.v = d._v;
            d._v = null;
          }
        });
      });
      
      
  </script>
</body>

</html>
like image 86
Mark Avatar answered Nov 12 '22 19:11

Mark


I found simple and built-in solutions for accept:

prop.select('div.input input').datum(function(d){obj[d.key]=(d.value=this.value);return d})

and revert:

upd(prop.datum(function(d){return(d)}))

I tried this already before, but there was an error on this line:

c.select('div.input input').attr("value", kv)

The correct code is here:

c.select('div.input input').property("value", kv)
like image 1
Pavel Gatnar Avatar answered Nov 12 '22 19:11

Pavel Gatnar