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

Question: Data Binding. #676

Closed
ovidius72 opened this issue Apr 23, 2017 · 17 comments
Closed

Question: Data Binding. #676

ovidius72 opened this issue Apr 23, 2017 · 17 comments
Labels
proposal type:feature A feature request

Comments

@ovidius72
Copy link

Right now I'm changing the component state with events. When a value changes (e.g. in an input tag) I use the on-change or on-keypress events to handle state changes. However in a form with a lot of states you need to have a lot of event handlers in the component class.
It gets unwieldy to have full control over all the business logic. It would be easier and clean to have an attribute like angular or vue.js (v-model, model.. or something like this) that takes a property of the state object and update it automatically.
I don't know if such a feature is already available but from the documentation I haven't seen anything like that.
Is it possible to implement a 2 way data binding out of the box? or, if not possible, can you suggest the best pattern to manage such cases?
Thanks.

@gilbert
Copy link
Contributor

gilbert commented Apr 23, 2017

Related: #528

@guilhermeaiolfi
Copy link

I'm evaluating markojs for my next project. I'm between vue.js, svelte.js and marko.js. I love the marko syntax and the way it accepts all javascript types as attributes (not just strings or extra markups). The only thing that I'm questioning right now is why there is no basic data bindings. It's not hard for a form have +50 fields, having one event and a function listener for every field will make my components very polluted with duplicated code.

I've read #528 and it's such a common task for all of us, that it should be built in.

@patrick-steele-idem
Copy link
Contributor

patrick-steele-idem commented Aug 21, 2017

@guilhermeaiolfi Do you have a particular proposal in mind? We are definitely open to ideas and I would agree that dealing with a complex form can get tedious. We are looking for user feedback and if there's a compelling proposal we would be interested in coordinating the effort to get it implemented. I think supporting a :bind modifier for an attribute has some promise since it could be a hint to the compiler to pull in data binding code at runtime. Fortunately, we have the ability to add new features without increasing the runtime weight for all users since we have full control over the Marko compiler.

@guilhermeaiolfi
Copy link

@patrick-steele-idem well, svelte use bind:value=''. Since marko and svelte share the same architecture (both compile code instead of being interpreted by a library layer), it may be worth to see how they do it. A quick look shows that they treat those as a special case: https://github.com/sveltejs/svelte/blob/93e51d6ef3bccc5a3948fc5f0dcfdde9d1f413ca/src/generators/dom/visitors/Element/Attribute.js#L53

That looks "dirty" to me. Maybe introducing a general way of binding and creating components for , , <textarea /> could abstract that complexity away.

@ianvonholt
Copy link
Contributor

I've had to do this with mixins to extend common functionality in components across a large project.

With form handling, I have an attribute that would essentially flag the input to bind to a particular form element and set key-up and or change events accordingly. I feel that some enhancements to the state variables in conjunction with some tag attributes would be a great starting place for two way data binding.

At this point, is there any concern about performance hits with adding data binding to components?

@guilhermeaiolfi
Copy link

guilhermeaiolfi commented Aug 25, 2017 via email

@ianvonholt
Copy link
Contributor

@guilhermeaiolfi I can't share the exact code that is used in-house. If I find myself free with some time this weekend I'll put a generic class, as an example, to get this going.

@patrick-steele-idem I'd be more then happy to help get this one implemented if there is a large enough interest.

@patrick-steele-idem
Copy link
Contributor

I'm very interested. I would like to explore what we can support in user land before merging something into marko core. I would like to see something that is completely declarative that allows binding of input fields (including both DOM inputs and maybe input from custom components) to state properties on the component.

@ianvonholt could you share some code how you are utilizing data binding (not necessarily the implementation)?

Also, for reference: https://github.com/capaj/react-bound

@ianvonholt
Copy link
Contributor

@patrick-steele-idem I'll show original Marko syntax and then the attributes I use. I kept it similar to Angular's ngModel.

Before:

<label for:key="productDisplayName">What is your first name?</label>
<input type="text" key="productDisplayName" value=input.name onKeyup('onKeyUp')  placeholder="Ex: John" no-update/>
<span class="error-note">${state.errorNote}</span>

A simple form element, before, would consist of a <label>, <input>, and error <span>. This had a function that waited for input to stop before the particular state was changed.

After:

<label for:model="productDisplayName">What is your first name?</label>
<input key:model="productDisplayName" placeholder="Ex: John" />
<span error:model="productDisplayName">$state.productDisplayNameError</span>

Here everything is simplified a little bit. The input key and state object to bind to are set with the same attribute. This also creates a state object with Error so we could set custom error messages should a validation step fail. We have removed the no-update since the state was always correctly being bound to the input, so it didn't matter if a re-render on the parent element, or component, happened at all.

@nmocruz
Copy link

nmocruz commented Sep 13, 2017

to me something like <input value:bind=object.propt /> or <input bind:value=object.propt is perfect. Is very expressive and easy to learn. bind:value looks more imperative and value:bind declarative. The declarative way is more consistent with markup language, but bind:value still markup and give the idea of an instruction to bind the value to the property.

@casssiahaluu
Copy link

@nmocruz it is interesting too. You could show any sample like that?

@austinkelleher austinkelleher added the type:feature A feature request label Sep 26, 2017
@mlrawlings
Copy link
Member

I like the syntax @nmocruz suggested (See #870 for why value:bind instead of bind:value).

Would we ever want to bind to something other than a state value? It would be pretty straightforward to implement this if we made that restriction and use the setStateFromEvent method suggested in #528

In

<input value:bind=state.address name="address" />

Out

<input value=state.address on-input('setStateFromEvent', 'address') name="address" />

@maxmilton
Copy link

maxmilton commented Dec 23, 2017

Since marko uses a syntax where attributes look like functions, e.g. on-event(), for(), etc., why not keep things consistent and use something like bind()? Visually this is quite clear it's not fancy html but something "magical" is happening in the background.

Restricting this syntax to only apply to state would make things cleaner too:

class {
  onCreate() {
    this.state = {
      uname: '',
    };
  }
}
<input bind('uname') type="text" name="username"/>

I've always been a fan of how v-model works in vue, in that vue chooses the correct value, event, and data (state) binding behind the scenes based on element tag and type. Developers can focus on being productive rather than trying to remember which cases to use which event/value or when to do special case handling etc.

Vue model source: https://github.com/vuejs/vue/blob/master/src/platforms/web/compiler/directives/model.js

This does obfuscate the data flow to the developer but most of the time that's not important. It does have a runtime byte size cost (maybe add a config flag to disable it? edit: marko is smart enough to only include modules when necessary, nice!). Debugging in browsers lets you step though the data flow in the framework when necessary and for edge cases devs can simply handle the state mapping and event handling themselves.

@linweigao
Copy link

I am looking for the 2 way binding to implement form as well. Any update?
@ianvonholt Do you have time to share a demo of the implementation?

@DylanPiercey
Copy link
Contributor

@rajat8266
Copy link

Do we have any conclusion here?

@DylanPiercey
Copy link
Contributor

@rajat8266 we've added two way binding support in the tags api preview, more info here.

It will be natively supported in Marko 6, but for now you need the preview.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal type:feature A feature request
Projects
None yet
Development

No branches or pull requests