aurelia / templating-binding

An implementation of the templating engine's Binding Language abstraction which uses a pluggable command syntax.
MIT License
32 stars 26 forks source link

Add one-way-out binding. #33

Closed MicahZoltu closed 7 years ago

MicahZoltu commented 9 years ago

Currently there is both one-way (in) binding two-way (in-out) binding. I would like a one-way binding that is out only. An example would be an input box where I want changes in the input box to apply to the bound variable, but I don't want changes to the bound variable to apply to the text in the input box.

The purpose of this would be primarily for clarity of intention in the code. If I have an input box that is marked as value.one-way-in, then it is more obvious to the developer that my intention is to populate that input box with text from the view-model. If an input box is marked as value.one-way-out then it is more obvious to the developer that my intention is to populate the view-model from the contents of the box (user input).

This is particularly relevant for custom elements where the author of the element may want to setup the default binding for a bindable to one-way-out. This would mean that when bound with .bind the user of the custom element would be able to read data out from the bindable attribute but they would not be able to change the variable and have those changes reflected in the custom element.

petermorlion commented 9 years ago

Another example is for a file upload. This won't work:

<input type="file" files.two-way="files"></input>

You will receive an error like:

setting a property that has only a getter
Vheissu commented 9 years ago

Came here to ask for the same thing. A one-way-out binding would be an incredibly helpful feature to have. I wonder if it is simply a matter of reversing the logic what is already in the codebase for one-way - I might actually look into this and dependending on time commitments, I might be able to make this work. If not, I would still love to see this feature.

EisenbergEffect commented 9 years ago

It shouldn't be too hard to add actually. @jdanyow What do you think?

Vheissu commented 9 years ago

If it helps anyone else, you can achieve a one-way-out binding by using a callback function. Say for example you have an input element and you only want to store the input from the element when the user types into a ViewModel variable. All you need to do is create a callback function on your ViewModel called inputChanged (or any name of your choosing) which will receive an event as its argument.

<input type="text" keyup.delegate="inputChanged($event)">

Then in your ViewModel:

export class ViewModel {
    inputVal = '';

    inputChanged(evt) {
        this.inputVal = evt.target.value;
    }   
}

Whenever a keyup event is fired on the text input, the function that you specified in your ViewModel is called with the $event object for the input. You can then access the value and store it however you will. This effectively achieves a one-way-out relationship. Ideally a binding would simply take this same concept, except you would be binding to a variable in your ViewModel instead of a callback function. I guess it would be a convenience thing more than anything.

jdanyow commented 9 years ago

grepped the code- looks like it would just be a change to a couple areas: mainly the Binding class and the SyntaxInterpreter. Definitely doable.

WillsonHaw commented 9 years ago

This would definitely be useful for custom elements as well. My use case: I have a custom element <foo> with a binding like <foo someattr.bind="attrval"> in the parent view. However, someattr gets set at creation time and modifies as the user interacts with the control. I want to be able to forward the value of foo's someattr out of the parent view (it's a collection of custom elements and just exposes the value for each element). However, as soon as I do @bindable attrval it is overriding the someattr that foo already set to undefined.

akircher commented 8 years ago

My two cents. It should mimic value converter syntax from-view & to-view. If we support both directions for one-way, we should deprecate value.one-way since it becomes ambiguous. We then replace it with value.to-view and value.from-view

EisenbergEffect commented 8 years ago

That's a nice recommendation. For compat, we can't remove one-way but we could alias it to to-view. @jdanyow Any thoughts on this?

jdanyow commented 8 years ago

sounds good to me

yv989c commented 8 years ago

Yes please! :+1:

CasiOo commented 8 years ago

To be honest I don't like view being part of the attribute name. I would much rather have it named like in wpf one-way-to-source and keep one-way

jdanyow commented 8 years ago

@CasiOo I think we're going to go with to-view and from-view but the good news is you can alias them very easily:

import {SyntaxInterpreter} from 'aurelia-templating-binding';

SyntaxInterpreter.prototype['one-way-to-source'] = SyntaxInterpreter.prototype['from-view'];
CasiOo commented 8 years ago

I never was a fan of the toView and fromView naming in the value-converter either. My value-converters are sometimes used outside the view, and has nothing to do with the view at all.

Thanks for the alias example, but I don't think it's a good idea to go against the naming the framework has decided.

mdurling commented 8 years ago

What's the status of this? What I would find useful is something like value.one-time="x" value.from-view="y"

So, for example, an input control could get its initial value from property "x" and any updates would be applied to a different property "y"

Is there a way to accomplish this with today's binding capabilities? .

jdanyow commented 8 years ago

@mdurling this will be implemented, just hasn't been high priority.

Today you can do something like this for your use-case:

<input value.one-time="x" input.delegate="y = $event.target.value">

<!-- or -->

<input value.one-time="x" change.delegate="y = $event.target.value">

<!-- or -->

<input value.one-time="x" change.delegate="y = $event.target.value" input.delegate="y = $event.target.value">

Another option would be to use a binding behavior but I think the code above might be a little more clear for your "different property" use-case.

SimonFarrugia commented 7 years ago

I really like aurelia binding language (dot notation) but I always thought the binding modes where somewhat lacking and too verbose. Borrowing from es5 getter/setter syntax, I propose .get and .set bindings. example:

<!-- sets input value, one-way --> <input value.set="firstname">

<!-- gets input value, one-way out --> <input value.get="firstname">

<!-- sets input value once, one-time --> <input value.set-once="firstname">

<!-- gets input value once, one-time out --> <input value.get-once="firstname">

cluka commented 7 years ago

What is the status of this?

EisenbergEffect commented 7 years ago

It's not correctly being worked on. We would welcome a community contribution.

On Mar 2, 2017 5:57 AM, "Luka" notifications@github.com wrote:

What is the status of this?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/aurelia/templating-binding/issues/33#issuecomment-283659787, or mute the thread https://github.com/notifications/unsubscribe-auth/AAIBnXa0lx0KIpOZGJkqd-rAbLbKMVn1ks5rhsrXgaJpZM4EVLtr .