Commit Graph

10 Commits

Author SHA1 Message Date
Ryan Nowak 15ba614e6f Remove old workaround @onclick and @bind
This change removes support for the old syntax used for event handlers
and two-way binding.

See the relevant issues for details on the new features and
improvements:

bind https://github.com/aspnet/Blazor/issues/409
event handlers https://github.com/aspnet/Blazor/issues/503

Along with this change we've removed a few additional things Blazor
could do that aren't part of Razor's usual syntax.

----

The features that was used to make something like:
```
<button @onclick(...) />
```

is an expression that's embedded in a an element's attribute. This
feature might be useful in the future if we want to support 'splatting'
arbitrary attributes into a tag, but the runtime support for this isn't
accessible outside the Blazor core.

----

The features that implement:
```
<button onclick=@{ } />
```

have been removed in favor of a better design for lambdas, method group
conversions and other things for event handler attributes.

use `<button onclick=@(x => ...} />` instead.

We think is a better approach in general, because we want the app
developer to write and see the parameter list.

----

Both syntactic features that have been removed have dedicated error
messages in the compiler. If you're porting old code it should help you
figure out what to do.
2018-04-10 16:54:15 -07:00
Ryan Nowak df13669362 Improvements for delegate types (#516)
* Improve support for more types of event handlers

Improves support for for other types of event handlers with eventargs
types derived from UIEventArgs. Additionally fleshes out the set of
event handler types.

This change improves support for using more specific event handler types
like:

```
<button onclick="@Clicked" />

@functions {
    public void Clicked(UIMouseEventArgs e) { ... }
}
```

And:
```
builder.AddAttribute(12, "onkeypressed", KeyPressed);

...

void KeyPressed(UIKeyboardEventArgs e) { ... }

```

In particular what got better is:
- overload resolution for the AddAttribute method
- performance of different cases for AddAttribute

-----

The runtime now treats delegates as one of three types:
- arbitrary delegate: not attached to DOM events, not tracked by
renderer
- UIEventHandler: can attach to DOM events, tracked by renderer, first
class in IHandleEvents
- UIEventHandler-like: can attach to DOM events, tracked by renderer,
requires some special runtime support.

The set of overloads on AddAttribute has been tuned with a few specific
cases in mind.

Lambda expressions in an attribute will be inferred as UIEventHandler
unless the compiler does something more specific. So for instance,
passing a lambda as an attribute value for a component, where the
component doesn't define a matching attribute, will always be inferred
as UIEventHandler.

We now support method-group to delegate conversion for methods that
accept a derived UIEventArgs type. This means you can use a signature
like `void KeyPressed(UIKeyboardEventArgs e)` without any compiler
magic, and this will work in the runtime as long as the event type
produced by the runtime matches.

We also allow user-defined UIEventArgs-derived types. There's a pattern
for this and it requires defining an extension method and delegate type.

The method-group to delegate conversion part required some doing. It
doesn't play well with generics (Action<T> where T : UIEventArgs)
doesn't work at all. Adding more actual overloads (as opposed to
extensions) would cause lambda cases we want to work to be ambiguous.

----

The performance win here is to remove the need for a 'wrapper' delegate
created by the event handler tag helper code. This wrapper is now
created by the runtime, but only *after* we have checked the frame for
changes. This requires more heavy lifting in the runtime, but has the
advantage of producing no-op diffs as often as possible.

You will still get some inefficient behavior if your component uses a
capturing lambda in an event handler, so don't do that.

* Add selenium logs to test output

* Minor feedback

* WIP
2018-04-09 13:21:12 -07:00
Ryan Nowak c3366bc956 Add event handlers as tag helpers
This change adds support for mapping DOM event handlers as tag helpers
that function in a bi-modal way.

This is a new first-class feature for DOM events, and replaces a few
workarounds like using `@onclick(...)` or `click=@{ ... }`. I haven't
removed those things yet, this is a first pass to get the new support
in, we'll remove those things when we're totally satisfied.

When used with a string like `<button onclick="foo" />` the result is
a simple HTML attribute .

But when used with an implicit expression like
`<button onclick="@Foo" />` or
`<button onclick="@(x => Clicked = true)" />` a C# function is bound to
the click event from the DOM.
2018-04-06 13:00:04 -07:00
Ryan Nowak d097190824 Add support for conditional attributes
Adds conditional attributes for HTML elements.

This means that an attribute with a 'false' .NET bool value or a null
.NET value of another type will not be rendered in the HTML.
2018-04-03 14:06:48 -07:00
Steve Sanderson b52912a460 Handle ternary expressions inside interpolated attributes. Fixes #446 2018-03-30 11:38:10 +01:00
Ryan Nowak 5b658c80a1 Replace @bind with bind-...
This change introduces a 'tag helper' that replaces @bind with custom
code generation that accomplishes roughly the same thing.

This feature lights up by dynamically generating tag helpers that are
visible to tooling and affect the code generation based on:
- pattern recognition of component properties
- attributes that create definitions for elements
- a 'fallback' case for elements

'bind' also supports format strings (currently only for DateTime) via
a separate attribute.

This change introduces the basic framework for bind and tooling support.
We know that we'll have to do more work to define the set of default
'bind' cases for the DOM and to flesh out the conversion/formatting
infrastructure.

This change gets us far enough to replace all of the cases we currently
have tests for :) with the new features. The old @bind technique still
works for now.

Examples:

@* bind an input element to an expression *@
<input bind="@SelectedDate" format="mm/dd/yyyy" />
@functions {
    public DateTime SelectedDate { get; set; }
}

@* bind an arbitrary expression to an arbitrary set of attributes *@
<div bind-myvalue-myevent="@SomeExpression">...</div>

@* write a component that supports bind *@

@* 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; }
}
2018-03-29 22:04:24 -07:00
Steve Sanderson c58df0b739 Temporary workaround for #219 ("data-" attributes don't compile) 2018-03-19 18:09:53 +00:00
Steve Sanderson 6b73892e78 Avoid culture assumption in SupportsTwoWayBindingForDateValuesWithFormatString test. Fixes #268 2018-03-15 13:25:52 +00:00
Ryan Nowak 601e7914f7 Implement components as tag helpers
Implements Component code generation and tooling support end to end
udditionally adds some default `@addTagHelper` directives to make
programming in Blazor a little nicer.

Components are discovered as Tag Helpers using Razor's extensibility
during the build/IDE process. This drives the code generation during
build and lights up a bunch of editor features.

Add
2018-03-14 11:23:41 +00:00
Ryan Nowak 6182e8448d Get rid of RazorCompiler
Adds a little more use of Razor extensibility.

Razor is a plugin model, so we can't be the 'first mover' for initiating
compilation in the build tools and IDE.

Reorganizes tests and fills out more reusable test infrastructure for
Razor-driven testing.

Adds tests for declaration-only configuration.
2018-03-14 11:23:40 +00:00