@@ -148,11 +148,11 @@ private IntermediateNode[] RewriteUsage(IntermediateNode parent, TagHelperProper
148
148
{
149
149
// Bind works similarly to a macro, it always expands to code that the user could have written.
150
150
//
151
- // For the nodes that are related to the bind-attribute rewrite them to look like a pair of
151
+ // For the nodes that are related to the bind-attribute rewrite them to look like a set of
152
152
// 'normal' HTML attributes similar to the following transformation.
153
153
//
154
154
// Input: <MyComponent bind-Value="@currentCount" />
155
- // Output: <MyComponent Value ="...<get the value>..." ValueChanged ="... <set the value>..." />
155
+ // Output: <MyComponent Value ="...<get the value>..." ValueChanged ="... <set the value>..." ValueExpression ="() => ...<get the value>..." />
156
156
//
157
157
// This means that the expression that appears inside of 'bind' must be an LValue or else
158
158
// there will be errors. In general the errors that come from C# in this case are good enough
@@ -171,8 +171,10 @@ private IntermediateNode[] RewriteUsage(IntermediateNode parent, TagHelperProper
171
171
node . AttributeName ,
172
172
out var valueAttributeName ,
173
173
out var changeAttributeName ,
174
+ out var expressionAttributeName ,
174
175
out var valueAttribute ,
175
- out var changeAttribute ) )
176
+ out var changeAttribute ,
177
+ out var expressionAttribute ) )
176
178
{
177
179
// Skip anything we can't understand. It's important that we don't crash, that will bring down
178
180
// the build.
@@ -340,7 +342,32 @@ private IntermediateNode[] RewriteUsage(IntermediateNode parent, TagHelperProper
340
342
changeNode . Children [ 0 ] . Children . Add ( changeExpressionTokens [ i ] ) ;
341
343
}
342
344
343
- return new [ ] { valueNode , changeNode } ;
345
+ // Finally, also emit a node for the "Expression" attribute, but only if the target
346
+ // component is defined to accept one
347
+ ComponentAttributeIntermediateNode expressionNode = null ;
348
+ if ( expressionAttribute != null )
349
+ {
350
+ expressionNode = new ComponentAttributeIntermediateNode ( node )
351
+ {
352
+ AttributeName = expressionAttributeName ,
353
+ BoundAttribute = expressionAttribute ,
354
+ PropertyName = expressionAttribute . GetPropertyName ( ) ,
355
+ TagHelper = node . TagHelper ,
356
+ TypeName = expressionAttribute . IsWeaklyTyped ( ) ? null : expressionAttribute . TypeName ,
357
+ } ;
358
+
359
+ expressionNode . Children . Clear ( ) ;
360
+ expressionNode . Children . Add ( new CSharpExpressionIntermediateNode ( ) ) ;
361
+ expressionNode . Children [ 0 ] . Children . Add ( new IntermediateToken ( )
362
+ {
363
+ Content = $ "() => { original . Content } ",
364
+ Kind = TokenKind . CSharp
365
+ } ) ;
366
+ }
367
+
368
+ return expressionNode == null
369
+ ? new [ ] { valueNode , changeNode }
370
+ : new [ ] { valueNode , changeNode , expressionNode } ;
344
371
}
345
372
}
346
373
@@ -394,11 +421,15 @@ private bool TryComputeAttributeNames(
394
421
string attributeName ,
395
422
out string valueAttributeName ,
396
423
out string changeAttributeName ,
424
+ out string expressionAttributeName ,
397
425
out BoundAttributeDescriptor valueAttribute ,
398
- out BoundAttributeDescriptor changeAttribute )
426
+ out BoundAttributeDescriptor changeAttribute ,
427
+ out BoundAttributeDescriptor expressionAttribute )
399
428
{
400
429
valueAttribute = null ;
401
430
changeAttribute = null ;
431
+ expressionAttribute = null ;
432
+ expressionAttributeName = null ;
402
433
403
434
// Even though some of our 'bind' tag helpers specify the attribute names, they
404
435
// should still satisfy one of the valid syntaxes.
@@ -415,6 +446,7 @@ private bool TryComputeAttributeNames(
415
446
// We expect 1 bind tag helper per-node.
416
447
valueAttributeName = node . TagHelper . GetValueAttributeName ( ) ?? valueAttributeName ;
417
448
changeAttributeName = node . TagHelper . GetChangeAttributeName ( ) ?? changeAttributeName ;
449
+ expressionAttributeName = node . TagHelper . GetExpressionAttributeName ( ) ?? expressionAttributeName ;
418
450
419
451
// We expect 0-1 components per-node.
420
452
var componentTagHelper = ( parent as ComponentIntermediateNode ) ? . Component ;
@@ -437,6 +469,12 @@ private bool TryComputeAttributeNames(
437
469
changeAttributeName = valueAttributeName + "Changed" ;
438
470
}
439
471
472
+ // Likewise for the expression attribute
473
+ if ( expressionAttributeName == null )
474
+ {
475
+ expressionAttributeName = valueAttributeName + "Expression" ;
476
+ }
477
+
440
478
for ( var i = 0 ; i < componentTagHelper . BoundAttributes . Count ; i ++ )
441
479
{
442
480
var attribute = componentTagHelper . BoundAttributes [ i ] ;
@@ -450,6 +488,11 @@ private bool TryComputeAttributeNames(
450
488
{
451
489
changeAttribute = attribute ;
452
490
}
491
+
492
+ if ( string . Equals ( expressionAttributeName , attribute . Name ) )
493
+ {
494
+ expressionAttribute = attribute ;
495
+ }
453
496
}
454
497
455
498
return true ;
0 commit comments