mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
refactor(compiler): add support for class property bindings (#50805)
Adds support for bindings of the form `[class.some-class]="isActive"` PR Close #50805
This commit is contained in:
parent
021025964a
commit
2f7072dc3f
11 changed files with 71 additions and 8 deletions
|
|
@ -158,10 +158,10 @@ import * as i0 from "@angular/core";
|
|||
export class MyComponent {
|
||||
}
|
||||
MyComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
||||
MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, selector: "my-component", ngImport: i0, template: `<div [style.color]></div>`, isInline: true });
|
||||
MyComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "0.0.0-PLACEHOLDER", type: MyComponent, selector: "my-component", ngImport: i0, template: `<div [class.color]></div>`, isInline: true });
|
||||
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyComponent, decorators: [{
|
||||
type: Component,
|
||||
args: [{ selector: 'my-component', template: `<div [style.color]></div>` }]
|
||||
args: [{ selector: 'my-component', template: `<div [class.color]></div>` }]
|
||||
}] });
|
||||
export class MyModule {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,8 +41,7 @@
|
|||
"failureMessage": "Incorrect template",
|
||||
"files": ["empty_class_bindings.js"]
|
||||
}
|
||||
],
|
||||
"skipForTemplatePipeline": true
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import {Component, NgModule} from '@angular/core';
|
||||
|
||||
@Component({selector: 'my-component', template: `<div [style.color]></div>`})
|
||||
@Component({selector: 'my-component', template: `<div [class.color]></div>`})
|
||||
export class MyComponent {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,11 @@ export enum OpKind {
|
|||
*/
|
||||
StyleProp,
|
||||
|
||||
/**
|
||||
* An operation to bind an expression to a class property of an element.
|
||||
*/
|
||||
ClassProp,
|
||||
|
||||
/**
|
||||
* An operation to bind an expression to the styles of an element.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -737,6 +737,7 @@ export function transformExpressionsInOp(
|
|||
case OpKind.Property:
|
||||
case OpKind.StyleProp:
|
||||
case OpKind.StyleMap:
|
||||
case OpKind.ClassProp:
|
||||
case OpKind.ClassMap:
|
||||
op.expression = transformExpressionsInExpression(op.expression, transform, flags);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ import {ListEndOp, NEW_OP, StatementOp, VariableOp} from './shared';
|
|||
/**
|
||||
* An operation usable on the update side of the IR.
|
||||
*/
|
||||
export type UpdateOp = ListEndOp<UpdateOp>|StatementOp<UpdateOp>|PropertyOp|AttributeOp|StylePropOp|
|
||||
export type UpdateOp =
|
||||
ListEndOp<UpdateOp>|StatementOp<UpdateOp>|PropertyOp|AttributeOp|StylePropOp|ClassPropOp|
|
||||
StyleMapOp|ClassMapOp|InterpolatePropertyOp|InterpolateAttributeOp|InterpolateStylePropOp|
|
||||
InterpolateStyleMapOp|InterpolateClassMapOp|InterpolateTextOp|AdvanceOp|VariableOp<UpdateOp>;
|
||||
|
||||
|
|
@ -154,6 +155,44 @@ export function createStylePropOp(
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A logical operation representing binding to a class property in the update IR.
|
||||
*/
|
||||
export interface ClassPropOp extends Op<UpdateOp>, ConsumesVarsTrait, DependsOnSlotContextOpTrait {
|
||||
kind: OpKind.ClassProp;
|
||||
|
||||
/**
|
||||
* Reference to the element on which the property is bound.
|
||||
*/
|
||||
target: XrefId;
|
||||
|
||||
/**
|
||||
* Name of the bound property.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Expression which is bound to the property.
|
||||
*/
|
||||
expression: o.Expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a `ClassPropOp`.
|
||||
*/
|
||||
export function createClassPropOp(
|
||||
xref: XrefId, name: string, expression: o.Expression): ClassPropOp {
|
||||
return {
|
||||
kind: OpKind.ClassProp,
|
||||
target: xref,
|
||||
name,
|
||||
expression,
|
||||
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
||||
...TRAIT_CONSUMES_VARS,
|
||||
...NEW_OP,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A logical operation representing binding to a style map in the update IR.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -300,8 +300,11 @@ function ingestPropertyBinding(
|
|||
value.expressions.map(expr => convertAst(expr, view.tpl)));
|
||||
view.update.push(attributeInterpolate);
|
||||
break;
|
||||
case e.BindingType.Class:
|
||||
throw Error('Unexpected interpolation in class property binding');
|
||||
// TODO: implement remaining binding types.
|
||||
case e.BindingType.Animation:
|
||||
default:
|
||||
// TODO: implement remaining binding types.
|
||||
throw Error(`Interpolated property binding type not handled: ${type}`);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -336,8 +339,15 @@ function ingestPropertyBinding(
|
|||
const attrOp = ir.createAttributeOp(xref, bindingKind, name, convertAst(value, view.tpl));
|
||||
view.update.push(attrOp);
|
||||
break;
|
||||
case e.BindingType.Class:
|
||||
if (bindingKind !== ir.ElementAttributeKind.Binding) {
|
||||
throw Error('Unexpected class binding on ng-template');
|
||||
}
|
||||
view.update.push(ir.createClassPropOp(xref, name, convertAst(value, view.tpl)));
|
||||
break;
|
||||
// TODO: implement remaining binding types.
|
||||
case e.BindingType.Animation:
|
||||
default:
|
||||
// TODO: implement remaining binding types.
|
||||
throw Error(`Property binding type not handled: ${type}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,10 @@ export function styleProp(name: string, expression: o.Expression, unit: string|n
|
|||
return call(Identifiers.styleProp, args);
|
||||
}
|
||||
|
||||
export function classProp(name: string, expression: o.Expression): ir.UpdateOp {
|
||||
return call(Identifiers.classProp, [o.literal(name), expression]);
|
||||
}
|
||||
|
||||
export function styleMap(expression: o.Expression): ir.UpdateOp {
|
||||
return call(Identifiers.styleMap, [expression]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ function populateElementAttributes(view: ViewCompilation, compatibility: boolean
|
|||
break;
|
||||
|
||||
case ir.OpKind.StyleProp:
|
||||
case ir.OpKind.ClassProp:
|
||||
ownerOp = lookupElement(elements, op.target);
|
||||
ir.assertIsElementAttributes(ownerOp.attributes);
|
||||
|
||||
|
|
|
|||
|
|
@ -124,6 +124,9 @@ function reifyUpdateOperations(_view: ViewCompilation, ops: ir.OpList<ir.UpdateO
|
|||
case ir.OpKind.StyleProp:
|
||||
ir.OpList.replace(op, ng.styleProp(op.name, op.expression, op.unit));
|
||||
break;
|
||||
case ir.OpKind.ClassProp:
|
||||
ir.OpList.replace(op, ng.classProp(op.name, op.expression));
|
||||
break;
|
||||
case ir.OpKind.StyleMap:
|
||||
ir.OpList.replace(op, ng.styleMap(op.expression));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ function varsUsedByOp(op: (ir.CreateOp|ir.UpdateOp)&ir.ConsumesVarsTrait): numbe
|
|||
case ir.OpKind.Property:
|
||||
case ir.OpKind.StyleProp:
|
||||
case ir.OpKind.StyleMap:
|
||||
case ir.OpKind.ClassProp:
|
||||
// Property bindings use 1 variable slot.
|
||||
return 1;
|
||||
case ir.OpKind.Attribute:
|
||||
|
|
|
|||
Loading…
Reference in a new issue