question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add 'bind-...' for two-way binding

See original GitHub issue

Summary

We’re adding a feature that replaces @bind(...) with something more first class for tooling.

Introducing bind-... for two-way binding:

<input bind="@CurrentValue" />
@functions {
    public string CurrentValue { get; set; }
}

bind-... attribute implements two-way binding to components and dom elements via a tag helper with special compile-time behavior. This means that intellisense, colorization, and completion know about bind-... and can provide contextual documentation and contextual completion.

image

note: the correct date format is actually yyyy-MM-dd. Do as I say, not as I do 😆

What is two-way binding?

If you’re not familiar with @bind (the thing being upgraded), this does two-way binding to both components and dom elements. This is like a macro, it doesn’t do anything you couldn’t do normally, but it should help you out 👍

Example:

<input bind="@CurrentValue" />
@functions {
    public string CurrentValue { get; set; }
}

Generates something like:

<input value="@CurrentValue" onchange="@((__value) => CurrentValue = __value)/>
@functions {
    public string CurrentValue { get; set; }
}

This means than when the component first runs, the value of the input element will come from the CurrentValue property. When the user types in the textbox, the CurrentValue property will be set to the changed value. This is why we call it two-way binding.

In reality the code generation is a little more complex because bind deals with a few cases of type conversions. But in principle, bind-... will associate the current value of an expression with a value attribute, and will handle changes via a change handler attribute. We expect to invest more in the runtime support in this area in the future, including better conversion, error handler, etc.

One additional point, the expression provided to bind-... should be an LValue, meaning that it’s something that can be assigned. Since this is code-generation, it works in places that the C# ref keyword doesn’t work.

React can do something similar: https://reactjs.org/docs/two-way-binding-helpers.html

Use cases

DOM elements

The most obvious usage of bind-... is for input elements of various types. You’re going to have lots of these 😆

That looks like this:

<input bind="@CurrentValue" />
@functions {
    public string CurrentValue { get; set; }
}

Or this:

<input type="checkbox" bind="@IsSelected" />
@functions {
    public bool IsSelected { get; set; }
}

For cases like this, we have a set of mappings between the structure of an input tag and the attributes that we need to set of the generated dom elements. These mappings are driven by attributes defined in code and are extensible.

Right now this set is minimal, but we plan to provide a good set of mappings out of the box for completion to lead you down the right path.

Format strings

You can also provide a format string - currently only for DateTime values.

<input type="date" bind="@StartDate" format="yyyy-MM-dd" />
@functions {
    public string StartDate { get; set; }
}

The format string will be used to convert to and from .NET values to the DOM attributes. We plan to enhance this area in the future, currently it’s restricted to DateTime. If you use this with an expression that isn’t a DateTime, expect some fireworks 🎆

Components

bind-... can also enhance components by recognizing component attributes that follow a specific pattern.

That looks like:

@* in Counter.cshtml *@
<div>...html omitted for brevity...</div>
@functions {
    public int Value { get; set; } = 1;
    public Action<int> ValueChanged { get; set; }
}

@* in another file *@
<Counter bind-Value="@CurrentValue" />
@functions {
    public int CurrentValue { get; set; }
}

The code generation for components is a little plainer. Since you’re calling into .NET code from .NET code, we expect the types to match.

Note that the component author doesn’t have to do anything special to enable this, we detect the bindables based on the names and types of the component properties.

Bind, user-defined

If you have a use for it, you can define your own mappings for bind-... and do things like this:

// in BindAttributes.cs
[BindElement("ul", "foo", "myvalue", "myevent")]
public class BindAttributes
{
}

@* in MyComponent.cshtml *@
<ul bind-foo="@SomeExpression" />

Bind, general case

bind-... also supports a fallback case that totally flexible. You can specify bind with any value attribute name and change handler attribute name.

<ul bind-myvalue-myevent="@SomeExpression" />

This will bind the current value of @SomeExpression to myvalue and a change handler lambda to myevent.

Next steps

The first change here introduces the general concept of bind as a language feature rather than a function call. I think that this works well for the cases that we have tested with @bind, but we need to do more work in the runtime to make it really complete.

This includes:

  • support conditional attributes
  • extend the set of bind-... mappings we provide by default
  • improve support for conversions
  • improve error handling for conversion failures

One of the next things we do will be to give the same treatment to @onclick and extend the set of default mappings we provide for event handlers.

There’s also a master list of improvements to the programming model for components described here: https://github.com/aspnet/Blazor/issues/1

That list doesn’t have much detail is only a general outline.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:16
  • Comments:21 (10 by maintainers)

github_iconTop GitHub Comments

9reactions
darilekcommented, Mar 28, 2018

IMHO these custom attributes (bind, format, converter, …) should be prefixed to distinguish them from the standard HTML attributes

6reactions
tdinuccicommented, Mar 29, 2018

I personally prefer this new “bind-” syntax to the @Bind previously. However is there even a need for the “bind-*” syntax?

I personally think Polymer has a very nice model for bindings.

To me the following transformation doesn’t feel intuitive - what does “bind” bind to?. Is it “value”, or “id”, or “type”, etc

<input bind="@CurrentValue" />

to

<input value="@CurrentValue" onchange="@((__value) => CurrentValue = __value)/>

If something like the Polymer syntax were used though then the binding is unambiguous:

<input value="{{CurrentValue}}"/>

I also wonder if things like string formatting (from top post):

<input type="date" bind="@StartDate" format="yyyy-MM-dd" />

Could be achieved with the string interpolation syntax. With the syntax below I don’t have to learn anything Blazor specific, I can just use my existing HTML and C# knowledge:

<input type="date" value="@StartDate:yyyy-MM-dd"/>

To take things a little further, the binding syntax could be augmented to signify one/two way bindings. Polymer syntax is:

One-way:

<input value="[[CurrentValue]]"/>

Two-way:

<input value="{{CurrentValue}}"/> I’m in no way suggesting that you do exactly the same thing as Polymer, I just think there syntax has a lot of nice aspects.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Two-way binding
Two-way binding gives components in your application a way to share data. Use two-way binding to listen for events and update values simultaneously...
Read more >
Two-way Data Binding in Angular 2 (v 11)
Here you will learn how to do two-way data binding in Angular. Two-way data binding refers to sharing data between a component class...
Read more >
Two-way data binding
If you want to use two-way data binding with custom attributes, you need to work with the @InverseBindingAdapter and @InverseBindingMethod ...
Read more >
Two-way binding in WPF
"One way" data binding is a binding from a source to a dependency property. The source must implement INotifyPropertyChanged, in order to get ......
Read more >
Two-way binding
To use two-way binding on a parameter simply prefix the HTML attribute with the text @bind- . This tells Blazor it should not...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found