지시문 @Input 필요
AngularJs에서는 필요한 지시 속성을 만들 수 있습니다.@Input을 사용한 Angular에서는 어떻게 해야 합니까?의사들한테는 그런 얘기 안 해
예.
@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;
}
공식 솔루션
Ryan Miglavs의 답변대로, 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
위의 데코레이터와 같이 대부분의 에디터는 컴포넌트 이름에 대한 툴팁 정보와 함께 데코레이터를 표시합니다.각이 지다
대체 솔루션의 경우– 아래를 참조해 주십시오.단, 위에서 설명한 단점은 없습니다.
여기에서는, getters/setters에 관한 솔루션을 소개합니다.을 한 수 IMHO가 입니다.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:
데코레이터가 있으면 더 쉽게 할 수 있어요.앱에서 다음과 같은 데코레이터를 정의합니다.
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;
}
설명:
아트리뷰트 If 성a
되어 있습니다 property - " " 。a
자신을 덮어쓰고 속성에 전달된 값이 사용됩니다. 않은 - init - property " - " - " property otherwise otherwise 。a
클래스 또는 템플릿에서 오류가 발생합니다.
주의: Getters/setters는 Angular의 컴포넌트/서비스 등에서 잘 동작하며, 이렇게 사용하는 것이 안전합니다.그러나 Angular 이외의 순수 클래스에서 이 방법을 사용할 때는 주의해야 합니다.문제는 typecript가 어떻게 getter/setters를 ES5로 전치하는가 하는 것입니다.getters/setters는 다음과 같이 할당됩니다.prototype
모든 에서 동일한 합니다.이 경우 모든 클래스의 인스턴스에서 동일한 프로토타입 속성을 변환합니다. '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 이런 것을 얻을 수 있습니다.
const instance1 = new ClassStub();
instance1.property = 'some value';
const instance2 = new ClassStub();
console.log(instance2.property); // 'some value'
체크인하다ngOnInit()
(생성자가 실행될 때 아직 설정되지 않은 값) 속성에 값이 있는지 여부.
Component({
selector: 'my-dir',
template: '<div></div>'
})
export class MyComponent implements OnInit, OnChanges {
@Input() a:number; // Make this a required attribute. Throw an exception if it doesnt exist
@Input() b:number;
constructor(){
}
ngOnInit() {
this.checkRequiredFields(this.a);
}
ngOnChanges(changes) {
this.checkRequiredFields(this.a);
}
checkRequiredFields(input) {
if(input === null) {
throw new Error("Attribute 'a' is required");
}
}
}
체크인 할 수도 있습니다.ngOnChanges(changes) {...}
값이 로 설정되어 있지 않은 경우null
https://angular.io/docs/ts/latest/api/core/OnChanges-interface.html 도 참조해 주세요.
이를 위한 공식적인 Angular 방법은 컴포넌트의 셀렉터에 필요한 속성을 포함하는 것입니다.예를 들어 다음과 같습니다.
/** Note: requires the [a] attribute to be passed */
Component({
selector: 'my-dir[a]', // <-- Check it
template: '<div></div>'
})
export class MyComponent {
@Input() a:number; // This property is required by virtue of the selector above
@Input() b:number; // This property is still optional, but could be added to the selector to require it
constructor(){
}
ngOnInit() {
}
}
이 방법의 장점은 개발자가 속성을 포함하지 않는 경우(a
템플릿 내의 컴포넌트를 참조할 때 코드가 컴파일되지 않습니다.이는 런타임 안전 대신 컴파일 시 안전성을 의미하며, 이는 매우 좋습니다.
단, 개발자가 수신하는 에러 메시지는 「not a known element(알려진 요소가 아닙니다)」이며,my-dir
이 네거티브는 위와 같이 @Component 데코레이터 위에 장식적인 코멘트를 추가하면 부분적으로 개선될 수 있으며 대부분의 에디터에서는 컴포넌트 이름에 대한 툴팁 정보와 함께 표시됩니다.Angular 오류 출력에는 도움이 되지 않습니다.
ihor에서 언급한 데코레이터의 접근방식을 시도했는데, 이 접근방식은 인스턴스가 아닌 클래스(TS 컴파일 후 프로토타입)에 적용되기 때문에 문제가 발생했습니다.즉, 데코레이터는 컴포넌트의 모든 복사본에 대해 한 번만 실행되거나 적어도 여러 인스턴스에서 작동하도록 할 방법을 찾을 수 없었습니다.
selector 옵션에 대한 문서를 다음에 나타냅니다.실제로는 매우 유연한 CSS 스타일의 셀렉터 입력(스위트워드)이 가능합니다.
Github 기능 요청 스레드에서 이 권장 사항을 찾았습니다.
필수 필드를 선언하는 매우 간단하고 적응적인 방법
많은 답변들이 이미 이 공식 기술을 보여주고 있다.여러 개의 필수 파일을 추가하려면 어떻게 해야 합니까?그런 다음 다음을 수행합니다.
단일 필수 필드
@Component({
selector: 'my-component[field1]',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.scss']
})
여러 필드 및 모든 필드가 필요합니다.
@Component({
selector: 'my-component[field1][field2][field3]',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.scss']
})
여러 개의 필드가 필요하지만 하나 이상의 필드가 필요합니다.
@Component({
selector: 'my-component[field1], my-component[field2], my-component[field3]',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.scss']
})
html에서 사용하는 방법은 다음과 같습니다.
<my-component [field1]="value" [field2]="value" [field3]="value"></my-component>
라이브러리를 사용하여 를 검증하는 것은 어떻습니까?다음 솔루션:
- 단시간에 실패한다(단순히 실패하는 것은
@input
컴포넌트에 의해 값이 처음 액세스 됩니다.) - 각도 양식에 이미 사용한 규칙을 재사용할 수 있습니다.
사용방법:
export class MyComponent {
@Input() propOne: string;
@Input() propTwo: string;
ngOnInit() {
validateProps<MyComponent>(this, {
propOne: [Validators.required, Validators.pattern('[a-zA-Z ]*')],
propTwo: [Validators.required, Validators.minLength(5), myCustomRule()]
})
}
}
유틸리티 기능:
import { FormArray, FormBuilder, ValidatorFn, FormControl } from '@angular/forms';
export function validateProps<T>(cmp: T, ruleset: {[key in keyof T]?: ValidatorFn[]} ) {
const toGroup = {};
Object.keys(ruleset)
.forEach(key => toGroup[key] = new FormControl(cmp[key], ruleset[key]));
const formGroup = new FormBuilder().group(toGroup);
formGroup.updateValueAndValidity();
const validationResult = {};
Object.keys(formGroup.controls)
.filter(key => formGroup.controls[key].errors)
.forEach(key => validationResult[key] = formGroup.controls[key].errors);
if (Object.keys(validationResult).length) {
throw new Error(`Input validation failed:\n ${JSON.stringify(validationResult, null, 2)}`);
}
}
다음과 같이 할 수 있습니다.
constructor() {}
ngOnInit() {
if (!this.a) throw new Error();
}
@ Required @ihor로 만들 수 .this
Object.defineProperty
this
는 데코레이터가 각 인스턴스에서 속성을 정의하도록 강제합니다.
export function Required(message?: string) {
return function (target: Object, propertyKey: PropertyKey) {
Object.defineProperty(target, propertyKey, {
get() {
throw new Error(message || `Attribute ${String(propertyKey)} is required`);
},
set(value) {
Object.defineProperty(this, propertyKey, {
value,
writable: true
});
}
});
};
}
저는 이렇게 해야 했습니다.
ngOnInit() {
if(!this.hasOwnProperty('a') throw new Error("Attribute 'a' is required");
}
참고로 @Output 디렉티브가 필요한 경우는, 다음과 같이 해 주세요.
export class MyComponent {
@Output() myEvent = new EventEmitter(); // This a required event
ngOnInit() {
if(this.myEvent.observers.length === 0) throw new Error("Event 'myEvent' is required");
}
}
다음은 덜 복잡하고 이해하기 쉬운 또 다른 TypeScript 데코레이터 기반 접근법입니다.또한 구성 요소 상속도 지원합니다.
// Map of component name -> list of required properties
let requiredInputs = new Map<string, string[]>();
/**
* Mark @Input() as required.
*
* Supports inheritance chains for components.
*
* Example:
*
* import { isRequired, checkRequired } from '../requiredInput';
*
* export class MyComp implements OnInit {
*
* // Chain id paramter we check for from the wallet
* @Input()
* @isRequired
* requiredChainId: number;
*
* ngOnInit(): void {
* checkRequired(this);
* }
* }
*
* @param target Object given by the TypeScript decorator
* @param prop Property name from the TypeScript decorator
*/
export function isRequired(target: any, prop: string) {
// Maintain a global table which components require which inputs
const className = target.constructor.name;
requiredInputs[className] = requiredInputs[className] || [];
requiredInputs[className].push(prop);
// console.log(className, prop, requiredInputs[className]);
}
/**
* Check that all required inputs are filled.
*/
export function checkRequired(component: any) {
let className = component.constructor.name;
let nextParent = Object.getPrototypeOf(component);
// Walk through the parent class chain
while(className != "Object") {
for(let prop of (requiredInputs[className] || [])) {
const val = component[prop];
if(val === null || val === undefined) {
console.error(component.constructor.name, prop, "is required, but was not provided, actual value is", val);
}
}
className = nextParent.constructor.name;
nextParent = Object.getPrototypeOf(nextParent);
// console.log("Checking", component, className);
}
}
언급URL : https://stackoverflow.com/questions/35528395/make-directive-input-required
'source' 카테고리의 다른 글
작업 이름 "..getProjectMetadata"가 없습니다. (0) | 2023.04.24 |
---|---|
정규식으로 파일 형식 검증 (0) | 2023.04.24 |
Flexbox: 가로와 세로 중앙 (0) | 2023.04.24 |
SQL Server에서 날짜/시간 중 일부를 제거하는 최선의 방법 (0) | 2023.04.24 |
스타일과 ControlTemplate의 차이점 (0) | 2023.04.24 |