AngularJs では、ディレクティブ属性を必須にすることができます。Angular で @Input を使用してこれを実行するにはどうすればよいですか? ドキュメントには記載されていません。
例えば。
@Component({
selector: 'my-dir',
template: '<div></div>'
})
export class MyComponent {
@Input() a: number; // Make this a required attribute. Throw an exception if it doesn't exist.
@Input() b: number;
}
ベストアンサー1
Angular 16以降の場合
ディレクティブ@Input()
は、何かを必須としてマークすることを直接サポートするようになりました。
@Input({ required: true }) myRequiredInput!: unknown;
この変更は、コンポーネントとディレクティブの両方に適用されます。
公式ソリューション (Angular 15 以下)
として答えたライアン・ミグラヴス著 – Angularの賢い使い方セレクター問題を解決します。
/** Note: requires the [a] attribute to be passed */
@Component({
selector: 'my-dir[a]', // <-- use attribute selector along with tag to ensure both tag name and attribute are used to "select" element by Angular in DOM
});
export class MyComponent {
@Input() a: number;
}
個人的には、コーディング時に追加の労力を必要としないため、ほとんどの場合、このソリューションを好みます。ただし、いくつかの欠点があります。
- スローされたエラーからどの引数が欠けているのか理解することはできません
- エラーは、引数が不足しているだけなのに、タグがAngularによって認識されないと言っているため、混乱を招きます。
これらの欠点は両方とも、上記のようにデコレータの上に装飾的なコメントを追加することで部分的に改善できます@Component
。ほとんどのエディターでは、コンポーネント名のツールヒント情報とともにそれが表示されます。ただし、Angular のエラー出力には役立ちません。
代替ソリューションについては、以下を参照してください。追加のコーディングが必要になりますが、上記のような欠点はありません。
そこで、ゲッター/セッターを使用した私のソリューションを紹介します。私見では、すべてが 1 か所で実行され、依存関係を必要としないため、これは非常にエレガントなソリューションですOnInit
。
解決策2
Component({
selector: 'my-dir',
template: '<div></div>',
});
export class MyComponent {
@Input()
get a() {
throw new Error('Attribute "a" is required');
}
set a(value: number) {
Object.defineProperty(this, 'a', {
value,
writable: true,
configurable: true,
});
}
}
解決策3:
それはできるかもしれないさらに簡単デコレータを使用します。アプリ内で次のようなデコレータを 1 回定義します。
function Required(target: object, propertyKey: string) {
Object.defineProperty(target, propertyKey, {
get() {
throw new Error(`Attribute ${propertyKey} is required`);
},
set(value) {
Object.defineProperty(target, propertyKey, {
value,
writable: true,
configurable: true,
});
},
configurable: true
});
}
そして、クラスの後半では、次のようにプロパティを必須としてマークする必要があります。
Component({
selector: 'my-dir',
template: '<div></div>',
});
export class MyComponent {
@Input() @Required a: number;
}
説明:
属性a
が定義されている場合、プロパティのセッターはa
それ自体をオーバーライドし、属性に渡された値が使用されます。それ以外の場合、つまりコンポーネントの初期化後、クラスまたはテンプレートで初めてプロパティを使用するときにa
、エラーがスローされます。
注記:ゲッター/セッターはAngularのコンポーネント/サービスなどではうまく機能し、このように使用しても安全です。しかし、このアプローチをAngular外の純粋なクラスで使用する場合は注意が必要です。問題は、Typescriptがどのようにゲッター/セッターをトランスパイルするES5 では、クラスのプロパティに割り当てられますprototype
。この場合、クラスのすべてのインスタンスで同じになるプロトタイプ プロパティを変更します。つまり、次のようになります。
const instance1 = new ClassStub();
instance1.property = 'some value';
const instance2 = new ClassStub();
console.log(instance2.property); // 'some value'