6
votes

I'm trying to write a generic view that handles custom fields in my app, but I'm having a hard time getting this to work. Here's the scenario - I have a fieldDef object which defines the custom fields, and a valueObject which has an array, customFields, which has the values. What I'm trying to do is something like this:

{{view Ember.TextField valueBinding="valueObject.customFields.[fieldDef.name]"}}

Obviously that doesn't work because it treats fieldDef.name as a literal. I've tried overriding the TextField class, but can't seem to get it to bind.

Any suggestions on how to accomplish this?

Thanks, Scott

3

3 Answers

6
votes

Ember can't bind to an array index, so you'll have to work around it. One solution is to limit yourself to a one-way binding, where your textfield updates the values hash. If you're planning to submit the form after the user presses a button, this should do the trick.

Define an array of field ids in your controller and a hash for their values to go in.

App.ApplicationController = Ember.Controller.extend({
  fieldIds: ['name', 'email', 'whatever'],
  fieldValues: {} // {name: 'user', email: 'user@...', ...}
});

Now extend Ember.TextField to update your values hash when a text field changes. You'll need to pass each instance a fieldId and a reference to the values hash from your controller.

App.TextField = Ember.TextField.extend({
  fieldId: null,
  values: null,

  valueChange: function() {
      var fieldId = this.get('fieldId');
      var values = this.get('values');
      if (values && fieldId) values[fieldId] = this.get('value');
  }.observes('value')
});

The template is simple.

{{#each fieldId in fieldIds}}
  <label>{{fieldId}}</label>
  {{view App.TextField fieldIdBinding="fieldId" valuesBinding="fieldValues"}}
  <br/>
{{/each}}

Here it is fleshed out in a jsfiddle.

1
votes

@ahmacleod great answer man. Just in case anyone is interested it works great extending select too:

import Ember from 'ember';

export default Ember.Select.extend({
  fieldId: null,
  values: null,

  valueChange: function() {
    var fieldId = this.get('fieldId');
    var values = this.get('values');
    if (values && fieldId) values[fieldId] = this.get('value');
  }.observes('value')
});

Call it as an normal component (components/dynamic-select.js)

{{#each id in fieldIds}}
   {{dynamic-select content=fieldIds fieldIdBinding="header"       
     valuesBinding="fields"}}
{{/each}}
1
votes

You can bind input values with dynamic keys(variables) of objects with help of mut helper now.

https://guides.emberjs.com/v2.6.0/templates/input-helpers/#toc_binding-dynamic-attribute

You can access it like this,

var Object = {};
var key = "firstName";

We can bind key in input helper like this,

{{input value=(mut (get Object key))}}

{{Object.firstName}} // Prints the dynamic value in textbox