Skip to content
This repository has been archived by the owner on Feb 16, 2021. It is now read-only.

proper way to create template for list item #109

Closed
ziweizhou opened this issue Apr 20, 2015 · 9 comments
Closed

proper way to create template for list item #109

ziweizhou opened this issue Apr 20, 2015 · 9 comments

Comments

@ziweizhou
Copy link

hello, is it possible to provide a sample template that I can use for create a list items? I am trying to customize the add,remove buttons like following screenshot.

2015-04-20 11 56 54

thank you.

@gcanti
Copy link
Owner

gcanti commented Apr 20, 2015

hello, is it possible to provide a sample template

Sure. Expanding my code in #108:

var listLayout = function (locals) {
  return (
    <div>
      <p>listLayout</p>
      <div>
        {
          locals.items.map(function (item) {
            return (
              <div>
                {item.input}
                {
                  item.buttons.map(function (button) {
                    return <button onClick={button.click}>{button.label}</button>;
                  })
                }
              </div>
            );
          })
        }
      </div>
      <button onClick={locals.add.click}>{locals.add.label}</button>
    </div>
  );
};

var options = {
  template: formLayout,
  fields: {
    pets: {
      template: listLayout, // <-- customize the list
      item: {
        template: petLayout
      }
    }
  }
};

@ziweizhou
Copy link
Author

Thank you very much. how can I contribute to write up wikis for others?

@gcanti
Copy link
Owner

gcanti commented Apr 20, 2015

how can I contribute to write up wikis for others

It would be very kind of yours. There is a new GUIDE.md file in the master branch root.

@ziweizhou
Copy link
Author

okay, i will look into it, btw, how to bind the onChange events on the fields? like in my screenshot, when user changes a currency, I would like to auto-pull an exchange rate against user's local currency and display it in the Rate field

@gcanti
Copy link
Owner

gcanti commented Apr 20, 2015

Search label:"dynamic forms", there are some issues which can help

@gcanti
Copy link
Owner

gcanti commented Apr 20, 2015

Just realized that rate and currency are in a list. This is challenging!
Here a quick example (tested with v0.5 but it should work with v0.4.10 as well).

var userCurrency = 'USD';

// fake rates
var rates = {
  EUR: 1,
  USD: 2,
  CHF: 3
};

function getRate(from, to) {
  // convert `form` to EUR
  var eur = 1 / rates[from];
  // convert EUR to `to`
  return eur * rates[to];
}

var Currency = t.enums.of('EUR USD CHF');

var ListItem = t.struct({
  currency: Currency,
  rate: t.Num
  // other fields here...
});

var Type = t.list(ListItem);

var App = React.createClass({

  getInitialState() {
    return {
      value: [ // some data for tests
        {currency: null, rate: null},
        {currency: 'CHF', rate: 1.5}
      ]
    };
  },

  onChange(value, path) {
    // check if the currency field is changed
    if (path[path.length - 1] === 'currency') {

      var index = path[path.length - 2];
      console.log('currency changed on item %s', index);
      var currency = value[index].currency;

      if (currency) {
        console.log('user didn\'t select the nullOption');

        // in order to trigger a re-rendering we must pass a copy of value
        // since the internal tcomb-form optimizations rely on ===
        var update = {};
        update[index] = {rate: {$set: getRate(userCurrency, currency)}}
        // update helpers of tcomb (see tcomb's docs)
        value = t.update(value, update);

        // trigger the re-rendering
        this.setState({value});
      }
    }
  },

  save() {
    var value = this.refs.form.getValue();
    if (value) {
      console.log(value);
    }
  },

  render() {

    return (
      <div>
        <Form ref="form"
          type={Type}
          onChange={this.onChange}
          value={this.state.value}
        />
        <button className="btn btn-primary" onClick={this.save}>Save</button>
      </div>
    );
  }

});

@ziweizhou
Copy link
Author

Thanks a lot, this is wonderful

@thekarel
Copy link

Let me note that unlike the template above, I had to include key props for the buttons, otherwise React gives a warning. On top of that, the buttons will only work if one passes the key property from locals.items (otherwise the order of list elements will not be updated, etc)

@gcanti
Copy link
Owner

gcanti commented Jul 14, 2015

@thekarel

Yep, thanks for noticing

var listLayout = function (locals) {
  return (
    <div>
      <p>listLayout</p>
      <div>
        {
          locals.items.map(function (item) {
            return (
              <div key={item.key}>
                {item.input}
                {
                  item.buttons.map(function (button, i) {
                    return <button key={i} onClick={button.click}>{button.label}</button>;
                  })
                }
              </div>
            );
          })
        }
      </div>
      <button onClick={locals.add.click}>{locals.add.label}</button>
    </div>
  );
};

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants