Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dynamic binding declaration ("dereferenced" binding) #4619

Closed
tkellen opened this issue Mar 29, 2014 · 18 comments
Closed

dynamic binding declaration ("dereferenced" binding) #4619

tkellen opened this issue Mar 29, 2014 · 18 comments

Comments

@tkellen
Copy link

tkellen commented Mar 29, 2014

Is there currently a way to declare a binding to a dynamically assigned property name in a template?

Here is a contrived example:

var App = Ember.Application.create({});

App.ApplicationController = Ember.ObjectController.extend({
  fields:  ['name', 'email'],
  name: 'tyler kellen',
  email: 'tyler@sleekcode.net'
});
{{#each field in fields}}
  {{field}}: {{input type="text" valueBinding="*field"}}<br>
{{/each}}

The resulting input elements should be bound to the name and email properties of the application controller instance used as context for the template.

Here is a JSBin showing that this does not currently work:
http://jsbin.com/toyih/8

If there is not currently a way to do this, would the Ember team be open to a PR that introduces a dereferencing operator as I've shown above? If yes, where is the logic for *Binding?

@stefanpenner
Copy link
Member

i kinda like the idea of:

{{#each field in fields}}
  {{field}}: {{input type="text" value=*field}}<br>
{{/each}}

@jonnii
Copy link

jonnii commented Mar 29, 2014

won't this be easy to do once we have sexpr? {{input type="text" value=(extractField this field)}}

@tkellen
Copy link
Author

tkellen commented Mar 29, 2014

Everything will be easy (and fugly) once we have s-expressions. I think a dereferencing operator makes total sense as a meaningful shorthand.

@endash
Copy link
Contributor

endash commented Mar 29, 2014

I move that we NOT call them sexpressions

@stefanpenner
Copy link
Member

@endash ya, we should call them s-expressions instead.

@wagenet
Copy link
Member

wagenet commented Apr 2, 2014

We don't need another ExpertSexChange on our hands.

@wagenet wagenet added the feature label Apr 2, 2014
@tkellen
Copy link
Author

tkellen commented Apr 3, 2014

Could someone point me in the right direction within the Ember codebase for making this feature addition?

@wagenet
Copy link
Member

wagenet commented Aug 6, 2014

@stefanpenner is this something you could provide guidance on?

@ahacking
Copy link

I was just looking for an answer for this exact problem, I have dynamic fields I need to enumerate and build a form with input controls.

It seems helpers don't get the value of the variable from #each passed in, and instead get passed the variable name (ie the string "field" in the example) NOT the actual value of field.

I was however able to figure out an interim solution for my custom input helper which allows me to dereference the #each loop variable. The following code is working for me:

  // indirect variable lookup
  var key, hash = options.hash;
  for (key in hash) {
    if (hash.hasOwnProperty(key)) {
      var deref = options.data.keywords[hash[key]];
      if (typeof deref === 'string') {
        hash[key] = deref;
      }
    }
  }

Note I am NOT using registerBoundHelper or makeBoundHelper in my particular case which may or may not limit the usefulness of the above, YMMV.

I would be keen to know where to start implementing general dereference support for bound properties but nothing particularly obvious jumped out on my initial scan through the code.

@stefanpenner any heads up on where to start with this?

@stefanpenner
Copy link
Member

@ahacking I believe @mmun's stream work plays into this nicely. (it either already does, or likely will need to)

I am a bit swamped right now to give this the thought it deserves, so I apologize for my quick and low value response.

@ahacking
Copy link

UPDATE: I was able to extract my initial solution into a standalone general purpose helper that can dereference a variable for use within the context of another helper.

Use as follows:

{{#each field in fields}}
  {{field}}: {{input type="text" valueBinding=(de-ref field)}}<br>
{{/each}}

Helper:

// app/helpers/de-ref.js
import Ember from 'ember';

export default function(name, options) {
  Ember.assert('Must specify a variable name', arguments.length === 2);
  var deref = options.data.keywords[name];
  if (typeof deref === 'string') { return deref; }
  return name;
}

So my questions:

  1. Is there a better/nicer general solution?
  2. Is there any interest in a PR for this as an out of the box Ember helper, or something for the guide at least ?

@mmun
Copy link
Member

mmun commented Oct 29, 2014

@ahacking Yes, there is a nice solution using subexpressions and streams that doesn't use the fooBinding syntax.

@ahacking
Copy link

@mmun Thanks, I guess I'll wait for the eventual 1.9 release to settle before cutting across to the new goodness as I have something that is functioning now and don't want to risk stability.

@mmun
Copy link
Member

mmun commented Oct 30, 2014

@ahacking Basically it would look like this:

{{input type="text" value=(deref field)}}
import { read } from "ember-metal/streams/read";

export default function derefHelper(params, options) {
  var view = options.data.view;
  var key = read(params[0]);
  return view.getStream(key);
}

With a little more work we could make it bound (e.g. if field changes).

@ahacking
Copy link

@mmun thanks for that. Can I ask is there any documentation on the streams stuff? Please pardon my ignorance as I am not aware of the features and benefits that the new streams work provides.

@mmun
Copy link
Member

mmun commented Oct 30, 2014

@ahacking There isn't any documentation yet. The stream rewrite is on canary and will be in 1.9, but it's still a private/internal API. The benefits are that is simplifies a lot of the template binding code and makes it simpler to generalize. For example, currently the query-params helper implementation has to manage all of its own bindings because it hasn't been streamified yet. If you're interested, you could work on that. You can find me on #emberjs as mmun if you want to chat.

@ahacking
Copy link

ahacking commented Nov 1, 2014

@mmun Thanks, when my workload lightens I will see what I can do.

@rwjblue
Copy link
Member

rwjblue commented Aug 9, 2015

This is possible now: http://rwjblue.jsbin.com/gavana/edit?html,js,output

    {{#each-in model as |field|}}
      <div>
        {{field}}: {{input value=(mut (get model field))}}
      </div>
    {{/each-in}}

@rwjblue rwjblue closed this as completed Aug 9, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants